我有一个关于React(Next)Context/Reducer的问题。我已经用Context和Reducer编写了组件,不明白为什么它不能像预期的那样工作。
问题是reducer的状态在useEffect中被正确地设置和记录,但是在按下调用上下文函数的键之后,状态似乎是一个较旧的副本。
pages/svg测试:
export default function SvgTest() {
return (
<>
<EditorContextProvider>
<SVGEditor />
</EditorContextProvider>
</>
)
}
components/svgTest/SVGEditor:
export default function SVGEditor() {
const {brightness} = useLocalStorage()
const {itemUp, right} = useEditorContext()
useEffect(() => {
function handleKeyDown(event: KeyboardEvent) {
switch (event.key) {
case 'ArrowUp':
itemUp()
break
case 'ArrowRight':
right()
break
}
}
document.addEventListener('keydown', handleKeyDown)
return () => {
document.removeEventListener('keydown', handleKeyDown)
}
}, [])
return (
<div style={{
display: 'grid', gridTemplateColumns: '2fr 5fr',
background: globals.brightness[brightness].background, height: 500,
}}>
</div>
)
}
components/svgTest/context:
const focuses = {
tree: 'tree',
form: 'form',
input: 'input',
}
type EditorAction = {
name: string,
payload?: any
}
type EditorState = {
focus: string
}
const initialTreeState: EditorState = {
focus: focuses.tree,
}
export function reducer(state: EditorState, action: EditorAction): EditorState {
const {name, payload} = action
switch (name) {
case 'focus': {
return {...state, focus: payload}
}
}
return state
}
export type EditorContext = {
editorState: EditorState
itemUp: () => void
right: () => void
}
const EditorContext = createContext<EditorContext>({} as EditorContext)
export function EditorContextProvider(props: { children: ReactNode }) {
const [editorState, dispatch] = useReducer(reducer, initialTreeState)
useEffect(() => {
console.log("logsntr", "editorState.effect", editorState)
}, [editorState])
function itemUp() {
console.log("logsntr", "editorState.up", editorState)
}
function right() {
dispatch({name: 'focus', payload: focuses.form})
}
return (
<EditorContext.Provider value={{
editorState, itemUp, right
}}>
{props.children}
</EditorContext.Provider>
)
}
export function useEditorContext() {
return useContext(EditorContext)
}
页面重新加载后的输出如下:
树
树
按下后:
树
按右后:
形式
按下后:
树
useState的行为也很奇怪。一个有效的解决方案是使用useRef,我假设未绑定状态不会在函数中反映,但这不应该是reducer的情况,对吗?它可能是Next的东西吗?
编辑:
我也尝试了useCallback,但结果相同:
const right = useCallback(() => {
dispatch({name: 'focus', payload: focuses.form})
}, [editorState])
1条答案
按热度按时间vngu2lb81#
我想我对嫌疑人的判断是对的:更新状态(useState或reducer)不会立即反映变化,而是在重新渲染之后才反映变化。而且重新渲染显然只在状态绑定到节点时发生。
这意味着在不重新呈现的情况下反射未绑定状态的唯一选项是使用useRef。
在这个方向提示:https://react.dev/reference/react/useReducer#avoiding-recreating-the-initial-state