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 = () => state
const 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() * 1000
return state
default:
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>
)
}
?
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 StoreState
return 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.value
Object.defineProperty(storeState, 'value', {
get: () => value,
set: (newValue) => {
value = newValue
updateView()
},
})
}
})
}
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
?