redux基础实现
myRedux
export const createStore = (reduce) => {if (typeof reduce !== 'function') throw new Error('Expected the reducer to be a function.')let state,listeners = []state = reduce()const getState = () => stateconst dispatch = (action) => {if(typeof action !== 'object' || typeof action.type !== 'string') throw new Error('Actions must be plain objects.')state = reduce(state, action)listeners.forEach(listener => listener())}const subscribe = (listener) => {if(typeof listener !== 'function') throw new Error('Expected the listener to be a function.')listeners.push(listener)return () => listeners = listeners.filter(l => l !== listener)}return {getState,dispatch,subscribe,}
}
使用
import React, { useEffect, useState } from 'react'
import { createStore } from './myRedux'const reduce = (state = { a: 123 }, action = {}) => {state = { ...state }switch (action.type) {case 'tset':state.a = Math.random() * 1000return statedefault:return state}}
const store = createStore(reduce)export default function Test() {const state = store.getState()const [_, foceUpdate] = useState(0)useEffect(() => {store.subscribe(() => {foceUpdate(Date.now())})}, [])const change = () => {store.dispatch({ type: 'tset' })}return (<div><h1>Test {state.a}</h1><button onClick={change} >change</button></div>)
}
模仿pinia方式管理
myPinia.js
export const createStore = (f) => {if (typeof f !== 'function') throw new Error('Expected a function')const state = f()watch(state)const proxy = new Proxy(state, {get: (target, prop) => {const v = target[prop]const isState = v instanceof StoreStatereturn isState ? v.value : v},set: () => state,})const userStore = () => {return proxy}return userStore
}const watch = (obj) => {Object.keys(obj).forEach((key) => {const storeState = obj[key]if (storeState instanceof StoreState) {let value = storeState.valueObject.defineProperty(storeState, 'value', {get: () => value,set: (newValue) => {value = newValueupdateView()},})}})
}class StoreState {constructor(value) {this.value = value}
}export const useStoreState = (value) => {return new StoreState(value)
}
let listeners = []
const updateView = () => listeners.forEach((f) => f())
export const subscribe = (f) => {if (typeof f !== 'function') throw new Error('Expected a function')if (!listeners.includes(f)) listeners.push(f)return () => (listeners = listeners.filter((l) => l !== f))
}
使用
import React, { useEffect, useState } from 'react'
import { createStore, useStoreState, subscribe } from './myPinia'const userStore = createStore(() => {let a = useStoreState(123)const change = () => {a.value++}return { a, change }
})export default function Test() {const [_, forceUpdate] = useState(0)useEffect(() => {subscribe(() => forceUpdate(Date.now()))}, [])const store = userStore()const change = () => {store.change()console.log(store.a);}return (<div><h1>test {store.a}</h1><button onClick={change} >change</button></div>)
}
不足的是,还是需要forceUpdate