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

1、mobx怎么对可观察对象作出反应

MobX 通常会对你期望的东西做出反应。 这意味着在90%的场景下,mobx “都可以工作”。 然而,在某些时候,你会遇到一个情况,它可能不会像你所期望的那样工作。 在这个时候理解 MobX 如何确定对什么有反应就显得尤为重要。

MobX 会对在 追踪函数执行 过程读取现存的可观察属性做出反应。
  • “读取” 是对象属性的间接引用,可以用过 . (例如 user.name) 或者 [] (例如 user['name']) 的形式完成。
  • “追踪函数” 是 computed 表达式、observer 组件的 render() 方法和 whenreaction 和 autorun 的第一个入参函数。
  • “过程(during)” 意味着只追踪那些在函数执行时被读取的 observable 。这些值是否由追踪函数直接或间接使用并不重要。

换句话说,MobX 不会对其作出反应:

  • 从 observable 获取的值,但是在追踪函数之外
  • 在异步调用的代码块中读取的 observable
  • MobX 追踪属性访问,而不是值

假设你有如下的 observable 数据结构(默认情况下 observable 会递归应用,所以本示例中的所有字段都是可观察的)。

`let message = observable({title: "Foo",author: {name: "Michel"},likes: ["John", "Sara"]
})` Copy

在内存中看起来像下面这样。 绿色框表示可观察属性。 请注意, 本身是不可观察的!
image.png
现在 MobX 基本上所做的是记录你在函数中使用的是哪个箭头。之后,只要这些箭头中的其中一个改变了(它们开始引用别的东西了),它就会重新运行。

2、没有封装成observer 组件

容器组件

import Change from './Change';
import Father from './Father';const Main = (props: any) => {return ()
}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 title: {message.title}author: {message.author.name}likes: {message.likes[0]}
}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 
}export default inject('store')(observer(Change));

store

import { observable, action } from 'mobx';class Store {@observable message = {title: 'Bar',author: {name: 'Susan'},likes: ['Michel']}@actionsetTitle = (title: string) => {this.message.title = title;}@actionsetName = (name: string) => {this.message.author.name = name;}@actionsetLikes = (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));

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

Father组件

const Father = (props: IProps) => {const { store } = props;const { message } = store as Store;return title: {message.title} {message.author.name}}>likes: {message.likes[0]}
}export default inject('store')(observer(Father));

Child组件

interface IProps {title: () => React.ReactNode;
}const Child = (props: IProps) => {const { title } = props;return {title()}
}export default Child;

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

如果 Child 来源于外部库的话,这通常不在你的掌控之中。在这种场景下,你可以用自己的无状态 observer 组件来包裹 div 解决此问题,或通过利用 组件:

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

另外一种方法可以使用 mobx-react 内置的 Observer 组件,它不接受参数,只需要单个的 render 函数作为子节点:

const Father = (props: IProps) => {const { store } = props;const { message } = store as Store;return title: {message.title} {() => {message.author.name}}}>likes: {message.likes[0]}
}

4、在本地字段中缓存 observable

一个常见的错误就是把间接引用的 observable 存储到本地变量,然后认为组件会作出反应。举例来说:

@inject('store')
@observer
class Father extends React.Component {author: { name: string; } | undefined;likes: string[] | undefined;title: string | undefined;constructor(props: IProps) {super(props);this.title = props.store?.message.title;this.author = props.store?.message.author;this.likes = props.store?.message.likes;console.log('title: ' ,this.title, 'author: ' ,this.author, 'likes: ', this.likes)}render() {return title: {this.title}name: {this.author?.name}likes: {this.likes && this.likes[0]}}
}export default Father;

组件会对authorlikes做出反应,不会对title做出反应,因为this.title = props.store?.message.title;是赋值,而this.author = props.store?.message.author;是赋引用,这个引用也是一个observable对象
image.png

换成函数组件

const Father = (props: IProps) => {const { store } = props;const { message } = store as Store;const title = message.title;const author = message.author;const likes = message.likes;return title: {title} {() => {author.name}}}>likes: {likes[0]}
}export default inject('store')(observer(Father));

发现组件即会对authorlikes做出反应,也会对title做出反应


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部