乐趣区

关于mobx:store变化了而页面取不到值mobx会对什么作出反应

1、没有封装成observer 组件

容器组件

import Change from './Change';
import Father from './Father';

const Main = (props: any) => {
  return (
    <div>
      <Father></Father>
      <Change></Change>
    </div>
  )
}

export default Main;

Father 组件

import {inject} from 'mobx-react';
import React from 'react';
import Store from '../../store/store';

interface IProps {store?: Store;}

const Father = (props: IProps) => {const { store} = props;
  const {message} = store as Store;

  return <div>
    <div>title: {message.title}</div>
    <div>author: {message.author.name}</div>
    <div>likes: {message.likes[0]}</div>
  </div>
}

export default inject('store')(Father);

Change 组件

import {Divider} from 'antd';
import {inject, observer} from 'mobx-react';
import React from 'react';
import Store from '../../store/store';

interface IProps {store?: Store;}

const Change = (props: IProps) => {const { store} = props;

  const {setName, setTitle, setLikes} = store as Store;

  return <div>
    <button onClick={() => setTitle('spin')}> 扭转 title</button>
    <button onClick={() => setName('tom')}> 扭转 name</button>
    <button onClick={() => setLikes('john')}> 扭转 likes</button>
  </div>
}

export default inject('store')(observer(Change));

store

import {observable, action} from 'mobx';

class Store {
  @observable message = {
    title: 'Bar',
    author: {name: 'Susan'},
    likes: ['Michel']
  }

  @action
  setTitle = (title: string) => {this.message.title = title;}
  
  @action
  setName = (name: string) => {this.message.author.name = name;}

  @action
  setLikes = (target: string) => {this.message.likes[0] = target;
  }
}

export default Store;

当点击扭转 title、name、likes 按钮时,store 中察看对象 message 的属性值扭转了,然而 Father 组件并没有从新渲染。因为 Father 组件并不是 observer 组件,只有封装成 observer 组件,mobx 才会对 render 函数(函数组件了解为 return 返回的 ReactNode)中 读取 现存的可察看属性做出反馈。

因而,只须要将 Father 组件封装成 observer 组件就能够解决

export default inject('store')(Father);
改后
export default inject('store')(observer(Father));

2、MobX 只会为数据是间接通过 render 存取的 observer 组件进行数据追踪

Father 组件

const Father = (props: IProps) => {const { store} = props;
  const {message} = store as Store;

  return <div>
    <div>title: {message.title}</div>
    <Child title={() => <div>{message.author.name}</div>}></Child>
    <div>likes: {message.likes[0]}</div>
  </div>
}

export default inject('store')(observer(Father));

Child 组件

interface IProps {title: () => React.ReactNode;
}

const Child = (props: IProps) => {const { title} = props;

  return <div>{title()}</div>
}

export default Child;

当扭转 store 中 message.author.name 时,页面并不会从新渲染。因为 div 实际上不是由 Father(有追踪的渲染) 渲染的,而是 Child。所以要确保 Child 的 title 能够正确对新的 message.author.name 作出反应,Child 应该也是一个 observer

如果 Child 来源于内部库的话,这通常不在你的掌控之中。在这种场景下,你能够用本人的无状态 observer 组件来包裹 div 解决此问题,或通过利用 <Observer>组件:

// 将 Child 改成 observer 组件
const Child = (props: IProps) => {const { title} = props;

  return <div>{title()}</div>
}

export default observer(Child);

另外一种办法能够应用 mobx-react 内置的 Observer 组件,它不承受参数,只须要 单个的 render 函数作为子节点:

const Father = (props: IProps) => {const { store} = props;
  const {message} = store as Store;

  return <div>
    <div>title: {message.title}</div>
    <Child title={() => <Observer>{() => <div>{message.author.name}</div>}</Observer>}></Child>
    <div>likes: {message.likes[0]}</div>
  </div>
}
退出移动版