DEV Community

bronxsystem
bronxsystem

Posted on

Context API preventing rerenders?

Hello All,

I am no react wizard and would appreciate some help please. I have tried googling but the answers arent exactly what I need or bit cryptic to me.

Using the context api. I have one function that calculates a value and a functional component to display the value. The functional component uses the useContext hook to get access to state and functions.

Do i simple using react.memo inside where the calculate function is or do i useMemo hook in the component? not sure how context api works with this.

appState where I have my functions I export provider with values added as object

return (
    <AppContext.Provider
      value={{
        output: state.output,
      }}
    >
      {props.children}
    </AppContext.Provider>
  );
};
export default CalcState;

because the values are in an object does that mean i have to use useCallback?

Top comments (4)

Collapse
 
saisandeepvaddi profile image
Sai Sandeep Vaddi
  1. Pass memoized value to provider.

  const memoizedValue = React.useMemo(() => ({output}), [output]); // <--- use useMemo. 

  return (
    <AppContext.Provider
      value={memoizedValue}        // <------ pass memoized value
    >
      {props.children}
    </AppContext.Provider>
  );
  1. Normally use useContext.
function DisplayComponent() {
  const contextValue = useContext(AppContext);
  const output = contextValue.output;

  return <div>{output}</div>;
}

React.useMemo and React.memo are different.

React.useMemo is a hook which you can use inside a functional component.

React.memo is a higher-order component. You will wrap your component with React.memo.

The component which is wrapped by React.memo checks if props are same and will return the previous rendered output if props didn't change.

For example taking the same code,

function Parent() {
  const contextValue = useContext(AppContext);
  const output = contextValue.output;

  return <Child output={output} />;
}
function Child({output}) {
  return <div>{output}</div>;
}

export default React.memo(Child);

The child component renders the first time using the passed output value. Next time, if it is asked to render, it checks if output prop is same as before, and if it is same, it will not re-render and instead gives the previously memozied component.

Collapse
 
bronxsystem profile image
bronxsystem • Edited

omg I love you. thank you so much. one question if ok.

I noticed in the example you did not pass the value as object, if i pass as object will it cause issue with useMemo? for example

    value={{
        output: state.output,
      }}
    >


`

Collapse
 
saisandeepvaddi profile image
Sai Sandeep Vaddi

I did pass the object. memoizedValue is an object.

const memoizedValue = React.useMemo(() => ({output}), [output]);

is same as

const memoizedValue = React.useMemo(() => { 
  return { output };
}, [output]);

So this will look like const memoizedValue = { output } which is an object.


It's better whatever object you pass in ContextProvider's value is memoized.

value={{
        output: state.output,
}}

is not receiving memoized value. Because the object {output: state.output} is not a memoized object. So even if state.output is unchanged, the {output: state.output} will not be the same as the previous value if the component that uses MyContext.Provider is re-rendered.

Thread Thread
 
bronxsystem profile image
bronxsystem

thank you very much this helps a lot