React 状态管理破解
每个应用程序都需要某种状态管理。让我们从最基本的开始,看看随着规模的扩大,情况会如何变化。
2.1 创建基本的全局商店
这里的想法是有一个useState
可以存储我们的状态并更新它的东西,然后我们将使用反应上下文将它传递给组件。
所以现在我们将创建一个名为的新上下文StoreContext
,其值中第一个项目将是商店本身,第二个项目将是 setStore,以便我们可以更新它。
import React, { createContext, useContext, useMemo, useState } from 'react'
const StoreContext = createContext()
export const StoreProvider = ({ children, initialState }) => {
const [store, setStore] = useState(initialState)
const contextValue = useMemo(() => [store, setStore], [store])
return (
<StoreContext.Provider value={contextValue}>
{children}
</StoreContext.Provider>
)
}
export const useStore = () => {
return useContext(StoreContext)
}
export default StoreContext
2.2 有些事情似乎不对劲
你的商店能容纳的数据量是有限的useState
,用 setStore 更新商店最终会变成一个 PIA。所以,我们useReducer
在这里添加一个,现在我们的代码看起来像这样:
import React, { createContext, useContext, useMemo, useReducer } from 'react'
const StoreContext = createContext()
export const StoreProvider = ({ children, initialState, reducer }) => {
const [store, dispatch] = useReducer(reducer, initialState)
const contextValue = useMemo(() => [store, dispatch], [store])
return (
<StoreContext.Provider value={contextValue}>
{children}
</StoreContext.Provider>
)
}
export const useStore = () => {
return useContext(StoreContext)
}
export default StoreContext
上下文的问题在于,每当它发生更改时,其下的整个树都会重新渲染,这可能会带来巨大的性能问题。所以,即使我们只是调度一个 action,我们的组件也会重新渲染。现在,为了解决这个问题,让我们创建一个不同的上下文来存储调度函数,并将其与useDispatch
hook 一起使用。
import React, { createContext, useContext, useReducer } from 'react'
const StoreContext = createContext()
export const DispatchContext = createContext()
export const StoreProvider = ({ initialState, reducer, children }) => {
const [store, dispatch] = useReducer(reducer, initialState)
return (
<DispatchContext.Provider value={dispatch}>
<StoreContext.Provider value={store}>{children}</StoreContext.Provider>
</DispatchContext.Provider>
)
}
export const useStore = () => {
return useContext(StoreContext)
}
export const useDispatch = () => {
return useContext(DispatchContext)
}
export default StoreContext
我们的使用方法是将App
第一个包裹在我们的组件中DispatchContext
,StoreContext
然后将第二个包裹在我们的组件中
import React, { useRef } from 'react'
import { useDispatch, useStore } from '@state/context-reducer'
const Example = () => {
const dispatch = useDispatch()
const store = useStore()
return (
<div className="my-3">
<p>{JSON.stringify(store)}</p>
<button onClick={() => dispatch({ type: 'increment' })}>
Dispatch
</button>
</div>
)
}
export default Example
2.3 更进一步
那么,只有一个全局状态?你可能会疑惑。
卷起袖子,这就是生成器函数发挥作用的地方。基本上,我们可以创建一个函数makeStore
,它接受 reducer 和 initialState,并为我们提供一个提供程序、一个 useStore 和一个 useDispatch,这样我们就可以轻松地创建多个存储。
import React, { createContext, useContext, useReducer } from 'react'
export default function makeStore(reducer, initialState) {
const StoreContext = createContext(null)
const DispatchContext = createContext(null)
const StoreProvider = ({ children }) => {
const [store, dispatch] = useReducer(reducer, initialState)
return (
<DispatchContext.Provider value={dispatch}>
<StoreContext.Provider value={store}>{children}</StoreContext.Provider>
</DispatchContext.Provider>
)
}
const useStore = () => {
return useContext(StoreContext)
}
const useDispatch = () => {
return useContext(DispatchContext)
}
return [StoreProvider, useStore, useDispatch]
}
现在我们可以建立任意数量的商店!
const [LayoutStore, useLayout, useLayoutDispatch] = makeStore(layoutReducer, { menuOpen: false })
const [TodoStore, useTodo, useTodoDispatch] = makeStore(todosReducer, [])
2.4 锦上添花
你可能会问,那么持久性又如何呢?
那怎么样?我说,只需在我们的函数中添加几行代码makeStore
:
export default function makeStore(reducer, initialState, key) {
const StoreContext = createContext(null)
const DispatchContext = createContext(null)
let finalInitialState = null
try {
finalInitialState = JSON.parse(localStorage.getItem(key)) || initialState
} catch(e) {}
const finalReducer = (state, action) => {
const newState = reducer(state, action)
localStorage.saveItem(key, JSON.stringify(newState))
return newState
}
// And now we use finalInitialState and finalReducer
// instead of reducer and initialState
}
这将使我们在开设所有商店时保持坚持。
等等,这难道不是全部在客户端吗?是的。所以在下一部分中,让我们看看如何将应用连接到服务器状态并使其正常运行。
文章来源:https://dev.to/patheticgeek/react-state-management-on-crack-55m8