社区精选 | 手写一个mini版本的React状态管理工具
SegmentFault
共 13191字,需浏览 27分钟
·
2022-10-15 15:20
今天小编为大家带来的是社区作者 夕水 的文章。看看他如何手写一个mini版本的React状态管理工具。
React Redux Mobx Hox
import { useState } from 'react'
const useCounter = (initialCount = 0) => {
const [count,setCount] = useState(initialCount);
const increment = () => setCount(count + 1);
const decrement = () => setCount(count - 1);
return {
count,
increment,
decrement
}
}
export default useCounter;
import React from 'react'
import useCounter from './useCounter'
const Counter = () => {
const { count,increment,decrement } = useCounter();
return (
<div className="counter">
{ count }
<button type="button" onClick={increment}>add</button>
<button type="button" onClick={decrement}>plus</button>
</div>
)
}
import React from 'react'
const App = () => {
return (
<div className="App">
<Counter />
<Counter />
</div>
)
}
const CounterContext = createContext();
export default CounterContext;
import React,{ createContext } from 'react'
import CounterContext from './CounterContext'
const App = () => {
const { count,increment,decrement } = useCounter();
return (
<div className="App">
<CounterContext.Provider value={{count,increment,decrement}}>
<Counter />
<Counter />
</CounterContext.Provider>
</div>
)
}
import React,{ useContext } from 'react'
import CounterContext from './CounterContext'
const Counter = () => {
const { count,increment,decrement } = useContext(CounterContext);
return (
<div className="counter">
{ count }
<button type="button" onClick={increment}>add</button>
<button type="button" onClick={decrement}>plus</button>
</div>
)
}
const Counter = createModel(useCounter);
export default Counter;
const { Provider,useModel } = Counter;
import React,{ createContext } from 'react'
import counter from './Counter'
const App = () => {
const { Provider } = counter;
return (
<div className="App">
<Provider>
<Counter />
<Counter />
</Provider>
</div>
)
}
import React,{ useContext } from 'react'
import counter from './Counter'
const Counter = () => {
const { count,increment,decrement } = counter.useModel();
return (
<div className="counter">
{ count }
<button type="button" onClick={increment}>add</button>
<button type="button" onClick={decrement}>plus</button>
</div>
)
}
// 导入类型
import type { ReactNode,ComponentType } from 'react';
import { createContext,useContext } from 'react';接下来定义一个唯一标识,用于确定传入的Context, 并且这个用来确定使用者使用Context时是正确使用的。 const EMPTY:unique symbol = Symbol();
export interface ModelProviderProps<State = void> {
initialState?: State
children: ReactNode
}
export interface Model<Value,State = void> {
Provider: ComponentType<ModelProviderProps<State>>
useModel: () => Value
}
export const createModel = <Value,State = void>(useHook:(initialState?:State) => Value): Model<Value,State> => {
//核心代码
}
//创建一个context
const context = createContext<Value | typeof EMPTY>(EMPTY);
const Provider = (props:ModelProviderProps<State>) => {
// 这里使用ModelProvider主要是不能和定义的函数名起冲突
const { Provider:ModelProvider } = context;
const { initialState,children } = props;
const value = useHook(initialState);
return (
<ModelProvider value={value}>{children}</ModelProvider>
)
}
const useModel = ():Value => {
const value = useContext(context);
// 这里确定一下用户是否正确使用Provider
if(value === EMPTY){
//抛出异常,使用者并没有用Provider包裹组件
throw new Error('Component must be wrapped with <Container.Provider>');
}
// 返回context
return value;
}
return { Provider,useModel }
// 导入类型
import type { ReactNode,ComponentType } from 'react';
import { createContext,useContext } from 'react';
const EMPTY:unique symbol = Symbol();
export interface ModelProviderProps<State = void> {
initialState?: State
children: ReactNode
}
export interface Model<Value,State = void> {
Provider: ComponentType<ModelProviderProps<State>>
useModel: () => Value
}
export const createModel = <Value,State = void>(useHook:(initialState?:State) => Value): Model<Value,State> => {
//创建一个context
const context = createContext<Value | typeof EMPTY>(EMPTY);
// 定义Provider函数
const Provider = (props:ModelProviderProps<State>) => {
const { Provider:ModelProvider } = context;
const { initialState,children } = props;
const value = useHook(initialState);
return (
<ModelProvider value={value}>{children}</ModelProvider>
)
}
// 定义useModel函数
const useModel = ():Value => {
const value = useContext(context);
// 这里确定一下用户是否正确使用Provider
if(value === EMPTY){
//抛出异常,使用者并没有用Provider包裹组件
throw new Error('Component must be wrapped with <Container.Provider>');
}
// 返回context
return value;
}
return { Provider,useModel };
}
export const useModel = <Value,State = void>(model:Model<Value,State>):Value => {
return model.useModel();
}
评论