0

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)

3 Answers 3

2

I found that my issue was to do with setState not firing any re-render by only mutating an object value in an array.

Instead of:

const setQuantity = (productId: string, quantity: number) => {
  let index = items.findIndex((item) => item.product.id == productId)
  items[index].quantity = quantity
  setItems(items)
}

I need to recreate the array like so:

const setQuantity = (productId: string, quantity: number) => {
  let index = items.findIndex((item) => item.product.id == productId)
  items[index].quantity = quantity
  setItems([...items])
}
Sign up to request clarification or add additional context in comments.

Comments

1

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>
)

7 Comments

Hello @Buggies thanks for your response, I've tried your code in codesandbox and works ! codesandbox.io/s/wonderful-chebyshev-6wx8sb but in my Nextjs App it doesn't it is driving me crazy, I can't find what's the error, maybe is for the server side rendering...I don't know I don't find anything related it.
@DevDuke I have it in nextJS app too so it should work, try use it like I updated the response. Thats only difference I can see.
thanks for your help, still doesn't work, I can see that I can update the array but when I go to the component where I need the context array of todos, is completely empty, is like reset or just take the initial values not the update values, I tried your updated response: <TodoContext.Consumer> {({ todos }) => todos.map((x: any) => <div key={x.id}>title: {x.title}</div>)} </TodoContext.Consumer>
and are you logging the todos in your provider if they really changed?
Last try I changed dependencies in useCallback and useEffect. Last chance is that you share your repo so I can try it
|
0

Final I crossed with the final solution, it was all about the next/link, you can find the right answer here React Context not updating value to pass to another page . I wasn't using the next/link to navigate to the updated component.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.