Solidjs状态更新
interface Running {
execute: () => void
dependencies: Set<Set<Running>>
}
const context = []
function subscribe(running: Running, subscriptions: Set<Running>) {
subscriptions.add(running)
running.dependencies.add(subscriptions)
}
export function createSignal<T>(value: T) {
const subscriptions = new Set<Running>()
const read = (): T => {
const running = context[context.length - 1]
if (running) subscribe(running, subscriptions)
return value
}
const write = (nextValue: T) => {
value = nextValue
for (const sub of [...subscriptions]) {
sub.execute()
}
}
return [read, write]
}
function cleanup(running) {
for (const dep of running.dependencies) {
dep.delete(running)
}
running.dependencies.clear()
}
export function createEffect(fn: () => void | unknown) {
const execute = () => {
cleanup(running)
context.push(running)
try {
fn()
} finally {
context.pop()
}
}
const running = {
execute,
dependencies: new Set<Set<Running>>(),
}
execute()
}
export function createMemo(fn: () => void | unknown) {
const [s, set] = createSignal()
createEffect(() => set(fn()))
return s
}
添加一个批量更新的函数
function flush(fn) {
if (typeof MessageChannel !== undefined) {
const { port1, port2 } = new MessageChannel();
port1.onmessage = fn;
port2.postMessage(null);
} else {
setTimeout(fn);
}
}
借用上述更新原理我们可以在 React中应用封装一个状态管理
export function createStore(initState) {
const createSetter = {}
const stateKeys = Object.keys(initState)
for (let i = 0
const [get, set] = createSignal(initState[stateKeys[i]])
createSetter[stateKeys[i]] = {get,set}
}
const dispatch = (state) => {
const dispatchKeys = Object.keys(state)
dispatchKeys.forEach(item => createSetter[item].set(state[item]))
}
const getStore = () => Object.keys(createSetter).reduce((pre,cur) => {
pre[cur] = createSetter[cur].get()
return pre
}, {})
const useStore = (stateKeys) => {
const [, forceUpdate] = useState({})
const updateRef = useRef(false)
const queue = useRef(0)
useEffect(() => {
createEffect(() => {
stateKeys.forEach(item => {
createSetter[item].get()
})
if (updateRef.current) {
queue.current += 1
queue.current === 1 && flush(() => {
queue.current = 0
forceUpdate({})
})
} else {
updateRef.current = true
}
})
}, [])
return getStore()
}
return { useStore, getStore, dispatch }
}
利用上述状态管理一个小例子
const { useStore, getStore, dispatch } = createStore({
count: 0,
grade: 0,
num: 0,
});
const handleAdd = () => {
const { count, grade, num } = getStore();
Promise.resolve().then(() => {
dispatch({
count: count+1,
grade: grade+1,
num: num + 1,
})
})
}
const handleGrade = () => {
const { grade } = getStore();
dispatch({
grade: grade+1,
})
}
function Counter() {
const { count, grade } = useStore(['count', 'grade']);
console.log(count, 'render----123count')
return (
<div>
<div>{count}-count</div>
<div>{grade}-grade</div>
<div onClick={handleAdd}>add</div>
</div>
);
}
function Grade() {
const { grade, num } = useStore(['grade', 'num']);
console.log(grade, 'render----123grade')
return (
<div>
<div>{grade}-grade</div>
<div>{num}-num</div>
<div onClick={handleGrade}>grade</div>
</div>
);
}
function App() {
return (
<div className="App">
<Counter />
<Grade />
</div>
);
}
借用上述更新原理我们可以在 React中应用封装另外一个状态管理
export function createStore<T>(initState: T) {
const storeContext = createContext<Record<string, any>>({})
const getStore = (createSetter) =>
Object.keys(createSetter).reduce((pre, cur) => {
pre[cur] = createSetter[cur].get()
return pre
}, {})
const useStore = (createSetter, stateKeys) => {
const [, forceUpdate] = useState({})
const updateRef = useRef<boolean>(false)
const queue = useRef<number>(0)
useEffect(() => {
createEffect(() => {
stateKeys.forEach((item) => {
createSetter[item].get()
})
if (updateRef.current) {
queue.current += 1
queue.current === 1 &&
flush(() => {
queue.current = 0
forceUpdate({})
})
} else {
updateRef.current = true
}
})
}, [])
return getStore(createSetter)
}
const Provider = ({ children }) => {
const [createSetter] = useState(() => {
const getSetter = Object.create(null)
const stateKeys = Object.keys(initState)
for (let i = 0
const [get, set] = createSignal(initState[stateKeys[i]])
getSetter[stateKeys[i]] = { get, set }
}
return getSetter
})
const dispatch = useCallback((state) => {
const dispatchKeys = Object.keys(state)
dispatchKeys.forEach((item) => createSetter[item].set(state[item]))
}, [])
const storeRef = useRef({
useStore: useStore.bind(null, createSetter),
dispatch,
getStore: getStore.bind(null, createSetter),
})
return <storeContext.Provider value={{ storeRef }}>{children}</storeContext.Provider>
}
const useSlice = <U extends keyof T>(stateKeys: U[]) => {
const { storeRef } = useContext(storeContext)
const { useStore, dispatch, getStore } = storeRef.current
return [useStore(stateKeys), dispatch, getStore]
}
return { Provider, useSlice }
}
从上面一个例子中我们可以看到每个组件只关心自己所关心的数据,不相关的数据更新,不会引起自身组件rerender😊