I'm working with nextjs and I want to try the React Context for a global variable, everything seems to be well added but the function for updating the Global Variable is not working, after spending the whole day reading and following documentation and blogs and stackoverflow I can't find any solution or where the problem is.
here is my code:
Provider.tsx:
import React, { createContext, useCallback, useState } from 'react'
export interface ITodo {
id: number
title: string
description: string
status: boolean
}
export type TodoContextTypeTEST = {
todos: ITodo[]
saveTodo: (todo: ITodo) => void
}
type Props = {
children: React.ReactNode
}
export const TodoContext = createContext<TodoContextTypeTEST>({ saveTodo: () => {}, todos: [] })
const TodoProvider: React.FC<Props> = ({ children }) => {
const [todos, setTodos] = useState<ITodo[]>([])
const saveTodo = useCallback(
(newTodo: ITodo) => {
console.log('here in the provider', newTodo)
setTodos([...todos, newTodo])
console.log('after save in the provider', todos)
},
[todos],
)
return <TodoContext.Provider value={{ todos, saveTodo }}>{children}</TodoContext.Provider>
}
export default TodoProvider
_app.tsx (wrapping the provider globally):
<TodoProvider>
<QueryClientProvider client={queryClient}>
<GlobalStyle />
<Layout>
<Component {...pageProps} />
</Layout>
<ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>
</TodoProvider>
Then inside of a form after the submit I added the save method:
const { saveTodo } = useContext(TodoContext) as TodoContextTypeTEST
and I call it with the data I want to update:
saveTodo({ id: 3, title: 'post 3', description: 'this is a description 3',status: false})
Then I check in another component and the data is not update:
const { todos } = useContext(TodoContext)
I think the problem can be with context value - it is recreated.
I looked at my code and docs and everywhere is used state as context value.
Try this:
const TodoProvider: React.FC<Props> = ({ children }) => {
const [todos, setTodos] = useState<ITodo[]>([])
const saveTodo = useCallback(
(newTodo: ITodo) => {
setTodos((oldTodos) => [...oldTodos, newTodo])
},
[setTodos],
)
const [contextValue, setContextValue] => useState({ todos, saveTodo })
useEffect(() => { setContextValue({ todos, saveTodo }) }, [todos, saveTodo])
return <TodoContext.Provider value={contextValue}>{children}</TodoContext.Provider>
}
then in component try this:
return (
<TodoContext.Consumer>{({ todos }) => ( render something )}</TodoContext.Consumer>
)