next.js React Reducer状态正确设置,但上下文中的函数没有反映它

3yhwsihp  于 2023-03-22  发布在  React
关注(0)|答案(1)|浏览(153)

我有一个关于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])
vngu2lb8

vngu2lb81#

我想我对嫌疑人的判断是对的:更新状态(useState或reducer)不会立即反映变化,而是在重新渲染之后才反映变化。而且重新渲染显然只在状态绑定到节点时发生。
这意味着在不重新呈现的情况下反射未绑定状态的唯一选项是使用useRef。
在这个方向提示:https://react.dev/reference/react/useReducer#avoiding-recreating-the-initial-state

相关问题