我有一个想法,要建立一个反应商店,有点像Vuex。我希望包装器组件接收一个值对象,并使用useContext提供一个对象返回,该对象将state和set附加到对象中的每个键。
例如,如果您将应用程序包装在类似<StoreProvider value={{ color: 'red' }}>的东西中,您可以在任何子const { color } = useContext(StoreContext)中使用它的值和color.state一起使用,然后调用color.set('blue')来全局更改该值。
我用useReducer写了一篇最好的尝试。
import React, {
createContext,
useContext,
useReducer
} from 'react'
const StoreContext = createContext(null)
export const useStoreContext = () => useContext(StoreContext)
export const StoreProvider = ({ children, value }) => {
const reducer = (state, action) => {
state[action.type].state = action.payload
return state
}
Object.keys(value).map(key => {
let state = value[key]
value[key] = {
state: state,
set: (setter) => dispatch({ type: key, payload: setter })
}
})
const [store, dispatch] = useReducer(reducer, value)
return (
<StoreContext.Provider value={store}>
{children}
</StoreContext.Provider>
)
}还有一个小演示,看看它是否有效:
import React from 'react'
import ReactDOM from 'react-dom'
import { StoreProvider, useStoreContext } from './store'
const App = () => {
const { color } = useStoreContext()
return (
<>
<h1>{color.state}</h1>
<button onClick={() => color.set('yellow')}>Change color</button>
<button onClick={() => console.log(color)}>Log</button>
</>
)
}
ReactDOM.render(
<StoreProvider value={{
color: 'orange'
}}>
<App />
</StoreProvider>,
document.getElementById('root')
)在上面的代码中,<h1>正确地呈现为‘橙色’,但在运行set('yellow')时不会更新为‘黄色’。但是,如果我记录颜色,state已经更新为“黄色”--我猜这意味着状态不是反应性的。
我做了什么蠢事吗?我很有反应能力,以前从未使用过useReducer。
发布于 2022-01-18 07:29:46
我觉得你错过了一个非常重要的反应点,那就是你永远不应该改变状态对象。state[action.type].state = action.payload是一种状态突变。在突变的基础上,您只需返回相同的状态对象。为了使状态更新正确工作,您必须返回新的对象引用。
const reducer = (state, action) => {
return {
...state, // <-- shallow copy state
[action.type]: {
...state[action.type], // <-- shallow copy nested state
state: action.payload,
}
};
}您还误用了array.map回调;您应该真正使用forEach --您正在迭代数组并发出副作用。array.map被认为是一个纯函数。
Object.keys(value).forEach(key => {
let state = value[key]
value[key] = {
state: state,
set: (setter) => dispatch({ type: key, payload: setter })
}
});我无法让您的初始value映射正确工作,似乎是做了一些额外的属性嵌套,这些属性与您在UI中访问或更新的方式不完全匹配。我建议计算初始还原器状态值的方法如下。迭代传递给上下文的value对象的键值对数组,减少为具有相同键的对象,值和setter正确嵌套。
const StoreProvider = ({ children, value }) => {
const reducer = (state, action) => {
return {
...state,
[action.type]: {
...state[action.type],
state: action.payload
}
};
};
const state = Object.entries(value).reduce(
(state, [key, value]) => ({
...state,
[key]: {
state: value,
set: (setter) => dispatch({ type: key, payload: setter })
}
}),
{}
);
const [store, dispatch] = useReducer(reducer, state);
return (
<StoreContext.Provider value={store}>{children}</StoreContext.Provider>
);
};
发布于 2022-01-18 00:24:39
我认为,只要要管理的状态没有那么复杂,就可以使用useState钩子简化逻辑:
export const StoreProvider = ({ children, value }) => {
const { color } = value;
const [currentColor, setCurrentColor] = useState(color);
return (
<StoreContext.Provider value={{ currentColor, setCurrentColor }}>
{children}
</StoreContext.Provider>
);
};下面是应用程序组件:
const App = () => {
const { currentColor, setCurrentColor } = useStoreContext();
return (
<>
<h1>{currentColor}</h1>
<button onClick={() => setCurrentColor('yellow')}>Change color</button>
<button onClick={() => console.log(currentColor)}>Log</button>
</>
);
};https://stackoverflow.com/questions/70748813
复制相似问题