社區(qū)精選 | 手寫一個(gè)mini版本的React狀態(tài)管理工具
今天小編為大家?guī)淼氖巧鐓^(qū)作者 夕水 的文章。看看他如何手寫一個(gè)mini版本的React狀態(tài)管理工具。
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>
)
}
// 導(dǎo)入類型
import type { ReactNode,ComponentType } from 'react';
import { createContext,useContext } from 'react';接下來定義一個(gè)唯一標(biāo)識,用于確定傳入的Context, 并且這個(gè)用來確定使用者使用Context時(shí)是正確使用的。 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> => {
//核心代碼
}
//創(chuàng)建一個(gè)context
const context = createContext<Value | typeof EMPTY>(EMPTY);const Provider = (props:ModelProviderProps<State>) => {
// 這里使用ModelProvider主要是不能和定義的函數(shù)名起沖突
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 }
// 導(dǎo)入類型
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> => {
//創(chuàng)建一個(gè)context
const context = createContext<Value | typeof EMPTY>(EMPTY);
// 定義Provider函數(shù)
const Provider = (props:ModelProviderProps<State>) => {
const { Provider:ModelProvider } = context;
const { initialState,children } = props;
const value = useHook(initialState);
return (
<ModelProvider value={value}>{children}</ModelProvider>
)
}
// 定義useModel函數(shù)
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();
}

評論
圖片
表情
