Search code examples
reactjsreact-hooksreact-contextreact-class-based-component

how to avoid re-rendering when passing the object into value of context.provider using React context


In class component when we want to pass the object to the value of context provider using react context, we have a way to avoid re-rendering issue. Below are the codes

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      text: "",
      contextState: {
        count: 0,
        increment: this.increment
      }
    };
  }

  increment = () => {
    this.setState({
      contextState: {
        ...this.state.contextState,
        count: this.state.contextState.count + 1
      }
    });
  };

  onChange = e => {
    const { value, name } = e.target;
    this.setState({ [name]: value });
  };

  render() {
    return (
      <CountContext.Provider value={this.state.contextState}>
        <div style={styles}>
          <input name="text" value={this.state.text} onChange={this.onChange} />
          <div>Count: {this.state.contextState.count}</div>
          <Container1 />
          <Container2 />
        </div>
      </CountContext.Provider>
    );
  }
}

We put this.state.contextState to value of CountContext.Provider. So when user types anything in input element and will not cause <Container1 /> and <Container2 /> re-rendered. Here is the code sandbox: https://codesandbox.io/s/qqx1jqk8mj?file=/src/index.js:260-1105

I am tring to convert it into hooks. Here is the code sandbox https://codesandbox.io/s/affectionate-gauss-duk64?file=/src/index.js but the counter is not working properly. May I please know which part is wrong? thanks


Solution

  • In your hook component, you just need to use the functional setState approach.

    setContextState(prevState=>newState)

    In your code: https://codesandbox.io/s/admiring-shtern-g6oll?file=/src/index.js

      const [contextState, setContextState] = useState({
        count: 0,
        increment: () => {
          setContextState(prev=>({
            ...prev,
            count: prev.count + 1
          }));
        }
      });
    

    The reason you need to do this is because the state value will never update because of the closure around it. contextState.count will always remain at 0 because it was the value when the state was originally set (0), and it won't change.