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

相关文章

如何在页面调用utility bar并传递参数至lwc组件

1.在app的utility item中添加lwc组件: 2.调用utility bar api的方式有两种: 方法一,通过lwc调用: import {LightningElement,api ,wire } from 'lwc';import { publish, MessageContext } from 'lightning/messageService';import Ca

SWAP作物生长模型安装教程、数据制备、敏感性分析、气候变化影响、R模型敏感性分析与贝叶斯优化、Fortran源代码分析、气候数据降尺度与变化影响分析

查看原文>>>全流程SWAP农业模型数据制备、敏感性分析及气候变化影响实践技术应用 SWAP模型是由荷兰瓦赫宁根大学开发的先进农作物模型,它综合考虑了土壤-水分-大气以及植被间的相互作用;是一种描述作物生长过程的一种机理性作物生长模型。它不但运用Richard方程,使其能够精确的模拟土壤中水分的运动,而且耦合了WOFOST作物模型使作物的生长描述更为科学。 本文让更多的科研人员和农业工作者

[环境配置]ubuntu20.04安装后wifi有图标但是搜不到热点解决方法

最近刚入手一台主机,暗影精灵8plus电竞主机,安装ubuntu后wifi怎么都搜不到热点,前后重装系统6次才算解决问题。这个心酸历程只有搞技术人才明白。下面介绍我解决过程。 首先主机到手后是个windows10系统,我用无线网连接了一下,可以正常上网,说明主机有无限网卡且正常。然后我就直接开始安装Ubuntu20.04了,安装成功后发现wifi有图标但是搜不到热点,我想是不是无线网卡驱动有没有

Weex入门教程之3,使用 Vue 开发 Weex 页面

环境安装 在这里简略地介绍下,详细看官方教程 Node.js 环境 Node.js官网 通常,安装了 Node.js 环境,npm 包管理工具也随之安装了。因此,直接使用 npm 来安装 weex-toolkit。 npm 是一个 JavaScript 包管理工具,它可以让开发者轻松共享和重用代码。Weex 很多依赖来自社区,同样,Weex 也将很多工具发布到社区方便开发者使用。

如何保证android程序进程不到万不得已的情况下,不会被结束

最近,做一个调用系统自带相机的那么一个功能,遇到的坑,在此记录一下。 设备:红米note4 问题起因 因为自定义的相机,很难满足客户的所有需要,比如:自拍杆的支持,优化方面等等。这些方面自定义的相机都不比系统自带的好,因为有些系统都是商家定制的,难免会出现一个奇葩的问题。比如:你在这款手机上运行,无任何问题,然而你换一款手机后,问题就出现了。 比如:小米的红米系列,你启用系统自带拍照功能后

c++的静态变化!

静态成员   对于非静态成员,一个类的每个对象都自己存有一个副本,每个对象根据自己拥有的非静态的数据成员来区别于其他对象。而静态成员则解决了同一个类的多个对象之间数据和函数的共享问题。   静态数据成员   静态数据成员的作用是:实现同一类的不同对象之间的数据共享。   #include<IOSTREAM>   using namespace std;   class Po

ViewPager+fragment实现切换页面(一)

如今的很多应用中都是下面有一排按钮,点击可以切换页面,滑动也可以切换页面。下面就来简单的实现这个功能。 思路 首先肯定是会用到viewpager这个控件,为了能够向下兼容,最好用v4包下的viewpager,Activity要继承FragmentActivity 其次用一个集合来存储所有的fragment页面在设置viewpager的适配器时,把存储fragment页面的list集合传入ada

【鸿蒙HarmonyOS NEXT】页面之间相互传递参数

【鸿蒙HarmonyOS NEXT】页面之间相互传递参数 一、环境说明二、页面之间相互传参 一、环境说明 DevEco Studio 版本: API版本:以12为主 二、页面之间相互传参 说明: 页面间的导航可以通过页面路由router模块来实现。页面路由模块根据页面url找到目标页面,从而实现跳转。通过页面路由模块,可以使用不同的url访问不同的页面,包括跳转到U