mobx 学习:hooks 与 mobx 结合

个人结合网上资料总结的一些比较适用的指南
更新于: 2022-08-18 12:21:39

安装

  • 会自行安装 mobx-react-lite
npm i -S mobx mobx-react
├─ mobx-react-lite@3.4.0
├─ mobx-react@7.5.2
└─ mobx@6.6.1

Hooks很强大,为何还需要Mobx?

  • 依赖传染性 —— 这导致了开发复杂性的提高、可维护性的降低
  • 缓存雪崩 —— 这导致运行性能的降低
  • 异步任务下无法批量更新 —— 这也会导致运行性能的降低

名词解释:依赖传染性

使用Hooks 编写代码时候,你必须清楚代码中 useEffect 和 useCallback的 “依赖项数组”的改变时机。

有时候,你的 useEffect 依赖某个函数的不可变性,这个函数的不可变性又依赖于另一个函数的不可变性,这样便形成了一条依赖链。一旦这条依赖链的某个节点意外地被改变了,你的 useEffect 就被意外地触发了。

个人理解:你得清楚知道,你的 useEffect/useCallback 类似这种,需要自己维护依赖数组的,每个依赖的触发时机,如果链条过长,就会变得像 OOP 的继承链过长一样的问题。

  • 如下: props.a/props.b 如果改变,会引起 console.log 的改变
  • 但外面 props.a 什么时候会改变,可能经过一个很长的链条,别人如何使用 Comp1 你无法控制
function Comp1(props) {
    useEffect(() => {
        console.log('useEffect');
    }, [props.a, props.b])
}

名词解释: 缓存雪崩

  • useRef 可以当成一个数据容器来用
  • 存储 DOM 只是其中一个用途
换句话说,造成这种原因主要是因为 Hooks 每次都会创建一个全新的闭包,而闭包内所有的变量其实都是全新的。
而每次都会创建闭包数据,而从性能角度来讲,此时缓存就是必要的了。而缓存又会牵扯出一堆问题。
说到底,也就是说没有一个公共的空间来共享数据,这个在 Class 组件中,就是 this,在 Vue3 中,那就是 setup 作用域。而 Hooks 中,除非你愿意写 useRef + ref.current 否则是没有办法找到共享作用域。

个人理解:作者是认为 hook 是一个全新的闭包(每次调用这个函数,是一个闭包,这一点没有错),但多个闭包没有 Classthis 这种共享数据的地方,但 React 提供了 useRef 这种共享的,他又不想用,所以出现了这个名词。

名词解释: 异步任务下无法批量更新

这个完全没有解释,也不知道他在说明什么问题,以后遇到再回看吧。

那些已经不推荐的

  • useLocalStore: 推荐用 useLocalObservable
  • useObserver: 推荐使用 <Observer />
  • inject: 不确定推荐使用什么,很少用这个api
# 不推荐的
import { useLocalStore } from 'mobx-react';

# 推荐的
import { Observer, useLocalObservable} from "mobx-react";
import React from 'react';
import { useObserver, Observer, useLocalStore } from 'mobx-react';
import { store } from './store';

// 方法1
function Demo1() { 
    const localStore = useLocalStore(() => store);
    return useObserver(() => <div onClick={localStore.setCount}>{localStore.count}</div>)
}

// 方法2 - 官方推荐的方式
function Demo2() { 
    const localStore = useLocalStore(() => store);
    return <Observer>{() => <span>{localStore.count}</span>}</Observer>
}

runInAction使用的必要性?

更新时间点: 2022-08-18 20:21:20

对于这里的用法,不太理解,甚至还没有认同,因为实际测试下来,

store.data = data;

store.loading = false; 

只会渲染一次,并不会造成多次渲染,所以,放在 runInAction 的理由到底是什么?

function AppWithMobx() {
    const store = useLocalStore(() => ({
        data: {},
        loading: true,
    }))
    useEffect(async () => {
        const data = await fetchData()
        runInAction(() => {
            // 这里借助 mobx 的 action,可以很好的做到批量更新,此时组件只会更新一次
            store.data = data
            store.loading = false
        })
    }, [])
    return useObserver(() => (/* ui */))
}

参考