2

According to the react documentation for context provider:

All consumers that are descendants of a Provider will re-render whenever the Provider’s value prop changes.

I am trying to update a context value from a sibling component (B) and read that update from sibling component (A).

Heres a simple example of what im trying:

import { useState, useContext, createContext } from "react";

export const AnalyseCtx = createContext({ greeting: "hello" });

export default function App() {
  const [context, setContext] = useState({ greeting: "hello" });

  console.log("rendering App");

  return (
    <div className="App">
      <AnalyseCtx.Provider value={{ context, setContext }}>
        <ComponentA />
        <ComponentB />
      </AnalyseCtx.Provider>
    </div>
  );
}

function ComponentA() {
  const analyseContext = useContext(AnalyseCtx);
  console.log("rendering ComponentA");
  return (
    <h4>I display the context value: {analyseContext.context.greeting}</h4>
  );
}

function ComponentB() {
  console.log("rendering ComponentB");
  const analyseContext = useContext(AnalyseCtx);
  analyseContext.setContext((prevState) => {
    prevState.greeting = "updated greeting";
    console.log("updated greeting: ", prevState);
    return prevState;
  });

  return <h4>I update context value</h4>;
}

I have also created a codesandbox to demonstrate the issue as well.

Sorry if this is a stupid question, but I've been stuck on this problem for a whole day. Thanks!

1 Answer 1

4

Component B is mutating the state object instead of returning a new state object reference. Shallow copy the previous state object into a new object reference and overwrite the properties you want to update.

Another issue is that component B is updating the context value as an unintentional side-effect. The update should be done from the useEffect hook so it's unconditionally enqueueing state updates and creating conditions for infinite render looping.

function ComponentB() {
  const { setContext } = useContext(AnalyseCtx);

  useEffect(() => {
    setContext(state => ({
      ...state,
      greeting: "updated greeting",
    }));
  }, []);

  return <h4>I update context value</h4>;
}

Edit react-context-update-not-re-rendering-component

Sign up to request clarification or add additional context in comments.

2 Comments

woah thank you! I feel dumb. I will accept the answer as soon as SO allows me to.
I have added a codesandbox sample to update context on a button click to demonstrate conditional updates. UseEffect with an empty dependency array will only update your context on mount of Component B. @Drew correctly mentioned that you should make shallow copies of your state. Read more about this under the subheading functional updates in the React Docs.

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.