Hooks
正式推出也有一年出头了,总结这一年中,本身使用过的Hooks
数据流方式react
目前接触过的数据流方案大体是2种方式redux
React
的数据流React
的数据流简单讲来,就是使用官方提供的Hooks
,好比最多见的useState
,这种方式也是咱们用的最多的api
经过useState
能将曾经类组件的state
值拆分为多个闭包
function App() {
const [state, setState] = useState({ foo: 0 });
const [loading, setLoading] = useState(false);
// ...
}
复制代码
使用useState
最大的好处是简洁明了,我的以为有2个缺点app
useState
后很差管理state
值过于复杂,在改变值时的合并是比较难处理的针对这两个小问题,也有另外一个hooks
解决框架
useReducer
能够说是官方简版redux
异步
const reducer = (state, { type, loading }) => {
if (type === "FOO") return { ...state, foo: 1 };
if (type === "SET_LOADING") return { ...state, loading };
return state;
};
function App() {
const [state, dispatch] = useReducer(reducer, { foo: 0, loading: false });
// ...
}
复制代码
与redux
还有一些小差别的就是react
提倡将初始值赋值在useReudcer
的参数中,而不是reducer
的state
ide
上面2种方式在单组件或者是父子层级组件使用仍是比较方便,若是想像redux
同样不关乎层级共享数据呢?在Hooks
中也提供了对应的方法工具
这种方式是我在这一年中使用最多的跨组件共享状态的方式了学习
const Context = createContext({});
const reducer = (state, { type, loading }) => {
if (type === "FOO") return { ...state, foo: 1 };
if (type === "SET_LOADING") return { ...state, loading };
return state;
};
function App() {
const [state, dispatch] = useReducer(reducer, { foo: 0, loading: false });
return (
<Context.Provider value={{ state, dispatch }}> // ...children </Context.Provider> ); } function Foo() { const { state, dispatch } = useContext(Context); // ... } 复制代码
这种方式能将本身的hooks
跨组件共享状态了,使用仍是比较方便,惟一的缺点就是本身须要使用createContext
来建立Context
而且挂载Provider
,会多一点步骤,也须要本身管理Context
,这能够说是纯手动
unstated-next
是一个200 字节的状态管理解决方案
function useCounter(initialState = 0) {
const [count, setCount] = useState(initialState)
return { count, setCount }
}
const Counter = createContainer(useCounter);
function Foo() {
const counter = Counter.useContainer();
// ...
}
function App() {
return (
<Counter.Provider> <Foo /> </Counter.Provider> ) } 复制代码
unstated-next
的实现使用的全是React
的api
,源码也短,下面会对他的源码进行分析
使用unstated-next
让咱们不须要本身建立和管理Context
了,从纯手动切换到了半自动
UmiJS中提供了一个useModel
方法,能够很方便的将hooks
全局使用,它的默认规则是src/models
下导出的hooks
会做用于全局
// src/models/count.ts
export default () => {
const [count, setCount] = useState(0);
return { count, setCount };
};
//
function App() {
const { count } = useModel('count');
// ...
}
复制代码
useModel
等因而省去了上面的useContext
和挂载<Prvoider>
的步骤,由框架处理了,在React Developer Tools能够看到最外层是有一个存了导出hooks
的值的Provider
的,我想他的实现方式应该和unstated-next
相似
从本身建立和管理Context
,挂载Provider
,到本身挂载Provder
,再到只须要写hooks
逻辑,过程就是手动——半自动——全自动
它的缺点就是范围局限了,仅限于UmiJS
框架
仅在使用过程当中我的的总结
优势
React
,没有额外的学习过程,简单易用缺点
数据是一个总体,不能作到精确刷新,一旦改变React
就会自动触发刷新
function Foo() {
const { state: { foo } } = useContext(Context);
// ...
}
function Bar() {
const { state: { bar } } = useContext(Context);
// ...
}
复制代码
若是在<Foo>
中调用了dispatch()
对state.foo
进行了更改,<Bar>
也会刷新
不基于React
的数据流实现就是数据存储不在React
里,数据改变不会直接触发组件刷新,而是经过其余的方式触发组件从新渲染,我只使用过2种
Redux
+React-Redux
DvaJs
在Hooks
推出后,React-Redux
也更新了Hooks
方法,使用useSelector()
来取得state
const Counter = () => {
const counter = useSelector(state => state.counter)
// ...
}
复制代码
它的优势是会精确刷新,不会像Context
同样致使总体刷新,由于useSelector
的从新渲染是本身控制的,而不是交给React
处理
Redux
+React-Redux
的缺点我想用过的都知道,就是须要管理不少文件
DvaJS
其实没有提供Hooks
的数据流方式
DvaJS
单独使用不多,基本是使用UmiJS
,实际在Umi
中有Hooks
的方式去获取数据
云谦大佬可能全身心投入UmiJS
开发,已经有很长一段时间没更新了,可是我以为做为一个集成度很是高的优秀数据流管理。
仅仅使用过2个月的我对DvaJS
的总结
优势
redux-sage
解决异步数据流问题redux
+react-redux
简单不少,再也不会有文件管理问题reducer
,让一些数据能够懒加载在类组件时代,没法拆分state
,类组件感受就很重,组件级state
多了也很难管理,Context
流行度也不算高,使用<Context.Consumer>
让组件更重了,后来有了contextType
也没有useContext
这么简洁,因此感受以前流行Redux
也是有缘由的,由于React
自己没有提供好的状态管理
Hooks
时代,一切都变得更简洁,官方提供了useReducer
这样的简洁版Redux
,同时组件级的state
也更简单,使用自定义的Hooks
,让数据和视图耦合更低了,useContext
+useReducer
的方案能够解决大部分须要共享状态的场景
使用了挺久的React
,我感受不少场景都不会全局共享状态,我如今作的项目就是后台管理系统,页面的数据也不会和别的页面关联,我都使用Context
一把梭了,因此我更喜欢轻量级的Hooks
数据流解决方案
有时候感受本身真的变成了搬运工,缺少本身的想法,就很呆,上面提到,我很长一段时间都是用useContext
来共享状态,每次都是手动挡,前几天忽然想,为何本身要作重复的工做,一搜果真有大佬已经写好了
// Provider传入的Props
export interface ContainerProviderProps<State = void> {
initialState?: State;
children: React.ReactNode;
}
// createContainer建立的Container类型
export interface Container<Value, State = void> {
Provider: React.ComponentType<ContainerProviderProps<State>>;
useContainer: () => Value;
}
// 建立一个Container
export function createContainer<Value, State = void>(
// 自定义数据的hook
useHook: (initialState?: State) => Value
): Container<Value, State> {
// Context用来传递数据
let Context = React.createContext<Value | null>(null);
function Provider(props: ContainerProviderProps<State>) {
// 用初始数据初始化自定义的hook
let value = useHook(props.initialState);
// 将hook的返回值赋值给Provider
return <Context.Provider value={value}>{props.children}</Context.Provider>;
}
// 使用Container,值就是自定义的hook的返回值
function useContainer(): Value {
let value = React.useContext(Context);
if (value === null) {
throw new Error("Component must be wrapped with <Container.Provider>");
}
return value;
}
return { Provider, useContainer };
}
export function useContainer<Value, State = void>(
container: Container<Value, State>
): Value {
return container.useContainer();
}
复制代码
源码很简单,就是一个闭包
做者说 “我相信 React 在状态管理方面已经很是出色”、“我但愿社区放弃像 Redux 这样的状态管理库,并找到使用 React 内置工具链的更好方法”,我以为颇有道理
虽然感受这篇没有什么技术含量,可是没有灵感,也有三周没有分享文章了
欢迎你们关注个人公众号~
参考文章:精读《React Hooks 数据流》