mobx-react-lite 是 MobX 和 React 的轻量级集成库,它提供了简单且高效的方式来在 React 组件中使用 MobX 状态管理。它的设计目标是减少与 React 的集成代码,优化性能,并且保持 MobX 的灵活性和声明性。mobx-react-lite 特别适用于功能组件(Function Components)和钩子(Hooks)模式,而不是传统的类组件和生命周期方法。
MobX 和 React 的关系
MobX 是一个状态管理库,它通过观测和响应式编程来帮助开发者管理应用的状态。MobX 使得状态的变更可以自动反映到 UI 中,从而简化了复杂的状态管理逻辑。
React 和 MobX 结合时,通常是通过组件将 MobX 中的状态映射到 UI 上,React 在此负责渲染视图,而 MobX 则负责状态的管理。mobx-react 是 MobX 和 React 的官方集成库,它的目标是帮助开发者将 MobX 状态与 React 组件进行连接。
然而,mobx-react-lite 是一个为 React 16.8+ 中的函数组件和 Hooks 提供优化的轻量级实现,它对 MobX 与 React 的集成做了优化,特别是在性能方面。
mobx-react-lite 主要特点
-
轻量级:
- 相比于
mobx-react,mobx-react-lite仅依赖于 React 和 MobX,因此它的体积更小,适合在 React 函数组件中使用。 - 不支持类组件和生命周期方法,只适用于函数组件和 hooks 模式。
- 相比于
-
优化性能:
mobx-react-lite使用 React 的useEffect和useState等 hook 来实现状态管理,从而减少了不必要的渲染。- 内部使用
React.memo和useObserver来确保只有在必要时才重新渲染组件,避免了不必要的渲染。
-
简化 API:
mobx-react-lite使用简单的 API,主要是通过observer高阶组件来使组件响应 MobX 状态变化,并通过useObserverhook 来处理状态变化。- 不需要
Provider和inject等复杂的 API,可以更简洁地集成 MobX。
-
支持 Hooks:
mobx-react-lite主要针对函数组件和 hooks。你可以通过useObserver或observer来观察状态的变化。- 它不需要复杂的类组件和生命周期方法,符合 React 的现代开发风格。
核心概念和使用方式
1. observer 高阶组件
observer 是 mobx-react-lite 中的主要工具,它是一个高阶组件(HOC),用于将组件包裹起来并使其响应 MobX 的状态变化。
import { observer } from 'mobx-react-lite';
import React from 'react';
// 一个简单的 MobX store
const store = observable({
count: 0,
increment() {
this.count += 1;
}
});
// 使用 observer 包裹组件,使其响应 MobX 状态
const Counter = observer(() => {
return (
<div>
<p>Count: {store.count}</p>
<button onClick={() => store.increment()}>Increment</button>
</div>
);
});
在上面的代码中,Counter 组件被 observer 包裹后,每当 store.count 的值发生变化时,Counter 组件会自动重新渲染。
2. useObserver Hook
useObserver 是一个用于在函数组件中直接观察 MobX 状态的 hook,它的功能和 observer 类似,但提供了更细粒度的控制,通常在更复杂的场景下使用。
import { useObserver } from 'mobx-react-lite';
import React from 'react';
// 一个简单的 MobX store
const store = observable({
count: 0,
increment() {
this.count += 1;
}
});
const Counter = () => {
return useObserver(() => (
<div>
<p>Count: {store.count}</p>
<button onClick={() => store.increment()}>Increment</button>
</div>
));
};
在上面的例子中,useObserver hook 返回一个响应式组件,自动监听 MobX 状态的变化。
3. observable
observable 是 MobX 中用于创建可观察状态的函数,它可以将对象、数组、或者简单的变量标记为响应式。
import { observable } from 'mobx';
// 创建可观察的对象
const store = observable({
count: 0,
increment() {
this.count += 1;
}
});
observable 会使 store.count 成为一个响应式值,当它改变时,所有依赖于 store.count 的组件都会自动更新。
4. action
在 MobX 中,action 是用于修改状态的函数。通常情况下,我们将状态的变更封装在 action 中,以便更好地跟踪和调试状态变化。
import { action, observable } from 'mobx';
const store = observable({
count: 0,
increment: action(function() {
this.count += 1;
})
});
action 可以帮助 MobX 更好地优化状态变更的追踪,尤其在进行复杂的多步操作时,它也有助于避免状态不一致的问题。
observer源码
export function observer<P extends object, TRef = {}>(
baseComponent: React.RefForwardingComponent<TRef, P>,
options?: IObserverOptions
) {
// The working of observer is explained step by step in this talk: https://www.youtube.com/watch?v=cPF4iBedoF0&feature=youtu.be&t=1307
if (isUsingStaticRendering()) {
return baseComponent
}
const realOptions = {
forwardRef: false,
...options
}
const baseComponentName = baseComponent.displayName || baseComponent.name
const wrappedComponent = (props: P, ref: React.Ref<TRef>) => {
return useObserver(() => baseComponent(props, ref), baseComponentName)
}
wrappedComponent.displayName = baseComponentName
// memo; we are not interested in deep updates
// in props; we assume that if deep objects are changed,
// this is in observables, which would have been tracked anyway
let memoComponent
if (realOptions.forwardRef) {
// we have to use forwardRef here because:
// 1. it cannot go before memo, only after it
// 2. forwardRef converts the function into an actual component, so we can't let the baseComponent do it
// since it wouldn't be a callable function anymore
memoComponent = memo(forwardRef(wrappedComponent))
} else {
memoComponent = memo(wrappedComponent)
}
copyStaticProperties(baseComponent, memoComponent)
memoComponent.displayName = baseComponentName
return memoComponent
}
这段代码定义了一个名为observer的函数,它是一个React高阶组件(HOC),用于将普通的React组件转换为响应式组件。这意味着包裹后的组件能够响应状态的变化,并在状态变化时重新渲染。
-
检查静态渲染:如果检测到当前环境是静态渲染(如服务器端渲染),则直接返回原始组件。
-
处理选项:合并用户提供的选项
options与默认选项,这里默认选项是{ forwardRef: false }。 -
获取组件名称:获取传入组件的
displayName或name属性,用于调试和显示。 -
定义包裹组件:定义了一个
wrappedComponent函数,它使用useObserver钩子来包裹原始组件baseComponent。useObserver钩子负责设置观察器,以便在组件依赖的可观察数据变化时触发更新。 -
设置displayName:设置
wrappedComponent的displayName属性,以便在React开发者工具中正确显示。 -
使用memo优化:使用
React.memo对wrappedComponent进行包裹,以避免不必要的重新渲染。如果选项中forwardRef为true,则使用React.forwardRef包裹wrappedComponent,以便能够正确地传递ref。 -
复制静态属性:使用
copyStaticProperties函数将原始组件的静态属性复制到memoComponent,以保留原始组件的所有静态方法和属性。 -
返回memoComponent:返回最终的
memoComponent,它是经过memo和可能的forwardRef包裹的响应式组件。
END
mobx-react-lite 是 MobX 和 React 的高效、轻量级集成库,适用于函数组件和现代的 React 开发风格。它优化了性能,减少了不必要的渲染,并通过 observer 和 useObserver 提供了简单的 API 来使组件响应 MobX 的状态变化。如果你正在使用 React 函数组件并且希望使用 MobX 作为状态管理方案,mobx-react-lite 是一个非常合适的选择。