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

2024-01-20 21:32

本文主要是介绍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 (<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']}@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 <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;

当改变storemessage.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>
}

4、在本地字段中缓存 observable

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

@inject('store')
@observer
class Father extends React.Component<IProps, any> {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 <div><div>title: {this.title}</div><div>name: {this.author?.name}</div><div>likes: {this.likes && this.likes[0]}</div></div>}
}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 <div><div>title: {title}</div><Child title={() => <Observer>{() => <div>{author.name}</div>}</Observer>}></Child><div>likes: {likes[0]}</div></div>
}export default inject('store')(observer(Father));

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

这篇关于store变化了而页面取不到值——mobx会对什么作出反应的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/627404

相关文章

找不到Anaconda prompt终端的原因分析及解决方案

《找不到Anacondaprompt终端的原因分析及解决方案》因为anaconda还没有初始化,在安装anaconda的过程中,有一行是否要添加anaconda到菜单目录中,由于没有勾选,导致没有菜... 目录问题原因问http://www.chinasem.cn题解决安装了 Anaconda 却找不到 An

电脑提示找不到openal32.dll文件怎么办? openal32.dll丢失完美修复方法

《电脑提示找不到openal32.dll文件怎么办?openal32.dll丢失完美修复方法》openal32.dll是一种重要的系统文件,当它丢失时,会给我们的电脑带来很大的困扰,很多人都曾经遇到... 在使用电脑过程中,我们常常会遇到一些.dll文件丢失的问题,而openal32.dll的丢失是其中比较

SpringBoot项目启动报错"找不到或无法加载主类"的解决方法

《SpringBoot项目启动报错找不到或无法加载主类的解决方法》在使用IntelliJIDEA开发基于SpringBoot框架的Java程序时,可能会出现找不到或无法加载主类com.example.... 目录一、问题描述二、排查过程三、解决方案一、问题描述在使用 IntelliJ IDEA 开发基于

Android WebView无法加载H5页面的常见问题和解决方法

《AndroidWebView无法加载H5页面的常见问题和解决方法》AndroidWebView是一种视图组件,使得Android应用能够显示网页内容,它基于Chromium,具备现代浏览器的许多功... 目录1. WebView 简介2. 常见问题3. 网络权限设置4. 启用 JavaScript5. D

SpringBoot项目启动错误:找不到或无法加载主类的几种解决方法

《SpringBoot项目启动错误:找不到或无法加载主类的几种解决方法》本文主要介绍了SpringBoot项目启动错误:找不到或无法加载主类的几种解决方法,具有一定的参考价值,感兴趣的可以了解一下... 目录方法1:更改IDE配置方法2:在Eclipse中清理项目方法3:使用Maven命令行在开发Sprin

Flutter监听当前页面可见与隐藏状态的代码详解

《Flutter监听当前页面可见与隐藏状态的代码详解》文章介绍了如何在Flutter中使用路由观察者来监听应用进入前台或后台状态以及页面的显示和隐藏,并通过代码示例讲解的非常详细,需要的朋友可以参考下... flutter 可以监听 app 进入前台还是后台状态,也可以监听当http://www.cppcn

MySQL表锁、页面锁和行锁的作用及其优缺点对比分析

《MySQL表锁、页面锁和行锁的作用及其优缺点对比分析》MySQL中的表锁、页面锁和行锁各有特点,适用于不同的场景,表锁锁定整个表,适用于批量操作和MyISAM存储引擎,页面锁锁定数据页,适用于旧版本... 目录1. 表锁(Table Lock)2. 页面锁(Page Lock)3. 行锁(Row Lock

禁止HTML页面滚动的操作方法

《禁止HTML页面滚动的操作方法》:本文主要介绍了三种禁止HTML页面滚动的方法:通过CSS的overflow属性、使用JavaScript的滚动事件监听器以及使用CSS的position:fixed属性,每种方法都有其适用场景和优缺点,详细内容请阅读本文,希望能对你有所帮助... 在前端开发中,禁止htm

MySQL8.0找不到my.ini如何解决

《MySQL8.0找不到my.ini如何解决》在配置MySQL主从复制时,发现找不到my.ini配置文件,通过检查路径和打开隐藏文件夹,最终在C:ProgramDataMySQLMySQLSer... 目录问题描述解决方法总结问题描述今天在配置mysql主从复制的时候发现,找不到my.ini这个配置文件。

使用JavaScript将PDF页面中的标注扁平化的操作指南

《使用JavaScript将PDF页面中的标注扁平化的操作指南》扁平化(flatten)操作可以将标注作为矢量图形包含在PDF页面的内容中,使其不可编辑,DynamsoftDocumentViewer... 目录使用Dynamsoft Document Viewer打开一个PDF文件并启用标注添加功能扁平化