I have a problem around React (Next) Context/Reducer. I've already written components with Context and Reducer and don't understand why it's not working as excpected.
The problem is that the reducer's state is set and logged correctly in useEffect but after a key press which calls a context function, the state seems to be a older copy.
pages/svgTest:
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)
}
The output is here after page reload:
tree
tree
After pressing up:
tree
After pressing right:
form
After pressing up:
tree
useState also behaves strangely. A solution that worked was with useRef und I supposed that an unbound state does not reflect in functions but that shouldn't be the case with the reducer, right? Could it be something with Next?
Edit:
I also tried useCallback but with the same result:
const right = useCallback(() => {
dispatch({name: 'focus', payload: focuses.form})
}, [editorState])