为什么需要数据流方案?
React本身只是一个DOM的抽象层,也就是使用组件来构建虚拟DOM,而开发大型应用,还需要解决数据流和组件通信的问题
通信问题
组件常见的通信如下
- 向子组件发消息
- 向父组件发消息
- 向兄弟组件/多层级嵌套的其他组件发消息
React只提供了一种通信手段:props传参,对于大型应用很不方便
数据流方案的演进
props组件传递 /context 上下文
React提供的最基本的单项数据流/跨层级数据流方案
- 缺点:大型应用使用不方便
redux/mobx
社区提供的应用级的顶层状态管理
- 缺点:概念繁多,需要在多个文件中穿插
dva
umi基于redux+redux-saga的数据流方案
- 缺点:概念繁多,需要借助connect高阶函数实现数据流和组件的绑定
react hooks
纯hooks的数据流方案
import { useState } from 'React'
const Counter = ()=>{
const [ count,setCount] = useSate<number>(0)
return (
<div onClick={()=>{
setCount(count=>count+1)
}}>{count}</div>
)
}
export default Counter
全局hooks的数据流
多个页面需要共享的状态
使用React的上下文管理相互关联的嵌套组件
- React.createContext
- useContext ```javascript import React, { useState, createContext, useContext } from “react”;
const Context = createContext
const Counter = ({}) => {
const { count, setCount } = useContext
return
export default function List() {
const [count, setCount] = useState(1);
return (
<a name="Y8CSU"></a>
### umi中的纯Hooks数据流
<a name="bnmtt"></a>
#### 使用umi model插件
> 安装umi的插件
```javascript
pnpm i @umijs/plugins
开启model插件配置
// config/confit.ts
import { defineConfig } from "umi";
export default defineConfig({
plugins: [require.resolve("@umijs/plugins/dist/model")],
model: {},
});
在 Umi 中约定存在 src/models 目录下面的文件,只要导出了自定义 hook ,会被识别为 model,添加到全局的 hooks 数据流中。可以在任何 React 上下文中,使用 useModel 取到你需要的数据
useModel 有两个参数 [性能优化]
- namespace 就是 hooks model 文件的文件名,如上面例子里的 counter。
- updater - 可选参数。在 hooks model 返回多个状态,但使用组件仅引用了其中部分状态,并且希望仅在这几个状态更新时 rerender 时使用(性能相关) ```javascript import { useState } from “react”; import { useModel } from “umi”;
// src/models/useCounterModel.tsx
export default function useCounterModel() {
const [count, setCount] = useState
// src/pages/Counter.tsx const Counter = ({}) => { const { count, setCount } = useModel(“counter”, (model) => ({ count: model.count, add: model.increment, }));
return
// src/pages/index.tsx
export default function List() {
const [count, setCount] = useState(1);
return (
<>
```
组件并不关心计数器 Model 中的 decrease 操作,只需要使用 Model 提供的 increment() 方法。于是我们传入了一个函数作为 useModel() 方法的第二个参数,该函数的返回值将作为 useModel() 方法的返回值。这样,我们过滤掉了 counter 这一频繁变化的值,避免了组件重复渲染带来的性能损失。