创建context
import React from 'react'
export default React.createContext({});
创建仓库
import React, { useMemo } from 'react';
import StoreContext from './context';
import { storeType } from './type';
export default function StoreProvider<T>(props: { children: React.ReactNode, data: T }) {
const store: storeType<T> = useMemo(() => {
let data = props.data;
return {
getData() {
return data;
},
setData(arg) {
const state = typeof arg === 'function' ? arg(data) : arg;
data = { ...data, ...state };
}
}
}, [props.data]);
return <StoreContext.Provider value={store}>{props.children}</StoreContext.Provider>
}
创建仓库相关的钩子
import React, { useCallback, useContext, useEffect, useReducer } from 'react'
import StoreContext from './context';
import { storeType, setDateType } from './type';
type dataType = <T>(selector: any, compare?: (obj1: any, obj2: any) => boolean) => T;
export const useStore = function <T>(): storeType<T> {
return useContext(StoreContext as any);
}
export function shallowEqual(objA: any, objB: any): boolean {
if (Object.is(objA, objB)) {
return true;
}
if (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) {
return false;
}
const keyA = Object.keys(objA);
const keyB = Object.keys(objB);
if (keyA.length !== keyB.length) return false;
for (let i = 0; i < keyA.length; i++) {
if (!Object.prototype.hasOwnProperty.call(objB, keyA[i]) || !Object.is(objA[i], objB[i])) {
return false;
}
}
return true;
}
const subscription: any[] = [];
export const useData: dataType = (selector, compare = shallowEqual) => {
const { getData } = useStore();
const [state, setState] = useReducer((oldState) => {
const newState = selector(getData());
if (!compare(oldState, newState)) {
return newState;
}
return oldState;
}, selector(getData()))
useEffect(() => {
subscription.push(setState);
return () => {
const index = subscription.indexOf(setState);
subscription.splice(index, 1);
}
}, [setState])
return state;
}
export const useDispatch: (<T>() => setDateType<T>) = () => {
const { setData } = useStore();
return useCallback((o) => {
setData(o);
subscription.forEach((fn) => fn());
}, [setData])
}
组件中使用
import { Button } from 'antd';
import React, { useEffect } from 'react'
import { useData, useDispatch } from '../store';
const StoreChildren = (props: any) => {
const dispatch = useDispatch();
const compare = (prev: any, next: any) => {
if (prev.group.length !== next.group.length) {
return false;
}
return true;
}
const data = useData<any>((state: any) => state, compare);
useEffect(() => {
console.log('引起组件更新了');
})
const handleDispatch = () => {
setTimeout(() => {
console.log('数据获取回来了');
const res = [1, 2, 3, 4, 5];
dispatch({ group: [...res] })
}, 1000)
}
return <div>
<Button onClick={handleDispatch}>dispatch</Button>
<Button onClick={() => dispatch({ b: 2 })}>dispatch</Button>
{data.b && <div>456</div>}
{
data.group?.map((_: any, idx: number) => {
return <p key={idx}>12313</p>
})
}
</div>
}
export default StoreChildren;