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

相关文章

springboot加载不到nacos配置中心的配置问题处理

《springboot加载不到nacos配置中心的配置问题处理》:本文主要介绍springboot加载不到nacos配置中心的配置问题处理,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑... 目录springboot加载不到nacos配置中心的配置两种可能Spring Boot 版本Nacos

IDEA下"File is read-only"可能原因分析及"找不到或无法加载主类"的问题

《IDEA下Fileisread-only可能原因分析及找不到或无法加载主类的问题》:本文主要介绍IDEA下Fileisread-only可能原因分析及找不到或无法加载主类的问题,具有很好的参... 目录1.File is read-only”可能原因2.“找不到或无法加载主类”问题的解决总结1.File

Python Selenium动态渲染页面和抓取的使用指南

《PythonSelenium动态渲染页面和抓取的使用指南》在Web数据采集领域,动态渲染页面已成为现代网站的主流形式,本文将从技术原理,环境配置,核心功能系统讲解Selenium在Python动态... 目录一、Selenium技术架构解析二、环境搭建与基础配置1. 组件安装2. 驱动配置3. 基础操作模

C#实现查找并删除PDF中的空白页面

《C#实现查找并删除PDF中的空白页面》PDF文件中的空白页并不少见,因为它们有可能是作者有意留下的,也有可能是在处理文档时不小心添加的,下面我们来看看如何使用Spire.PDFfor.NET通过C#... 目录安装 Spire.PDF for .NETC# 查找并删除 PDF 文档中的空白页C# 添加与删

电脑找不到mfc90u.dll文件怎么办? 系统报错mfc90u.dll丢失修复的5种方案

《电脑找不到mfc90u.dll文件怎么办?系统报错mfc90u.dll丢失修复的5种方案》在我们日常使用电脑的过程中,可能会遇到一些软件或系统错误,其中之一就是mfc90u.dll丢失,那么,mf... 在大部分情况下出现我们运行或安装软件,游戏出现提示丢失某些DLL文件或OCX文件的原因可能是原始安装包

解决Maven项目idea找不到本地仓库jar包问题以及使用mvn install:install-file

《解决Maven项目idea找不到本地仓库jar包问题以及使用mvninstall:install-file》:本文主要介绍解决Maven项目idea找不到本地仓库jar包问题以及使用mvnin... 目录Maven项目idea找不到本地仓库jar包以及使用mvn install:install-file基

SQL server配置管理器找不到如何打开它

《SQLserver配置管理器找不到如何打开它》最近遇到了SQLserver配置管理器打不开的问题,尝试在开始菜单栏搜SQLServerManager无果,于是将自己找到的方法总结分享给大家,对SQ... 目录方法一:桌面图标进入方法二:运行窗口进入方法三:查找文件路径方法四:检查 SQL Server 安

找不到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 开发基于