Seth Killian
Seth Killian

Reputation: 963

How to React Performance Optimize Re-Renders With Timer?

So I'm at a bit of a loss here for what to do and would love some recommendations.

I have a quizzing app that has a timer for a question. The parent contains the timer object which uses a callback to set the number of seconds remaining like so:

   const [seconds, setSeconds] = React.useState<number>(null);
   const timer = React.useRef<Timer>(new Timer({duration: 10, callback: i => setSeconds(i)}));

   ...

   return (
      <Context value={seconds}>
       ...

   )

The parent passes the seconds around to the descendants through a context because a child and grandchild both need access to the number of seconds remaining to show a timer.

The problem is that the update interval is every .1 seconds, and as a result the children and all subsequent descendants rerender which is a huge issue.

Is there a way that I can only have only the things that rely on the timer rerender?

I have all of my components wrapped in React.useMemo and am accessing the seconds with React.useContext.

Upvotes: 1

Views: 953

Answers (1)

Joseph D.
Joseph D.

Reputation: 12174

The problem is that the update interval is every .1 seconds, and as a result the children and all subsequent descendants rerender which is a huge issue.

This isn't entirely true. Only the specific context consumers will re-render based on value changes.

Is there a way that I can only have only the things that rely on the timer rerender?

Aside from using Context, Yes there is another way.

  1. Extract a TimerComponent from your context.

  2. Use redux to dispatch onTimerChange action from your TimerComponent

// in mapDispatchToProps
updateTimer = (duration) => {
  dispatch({ action: 'TIMER_UPDATED', payload: { duration }});
}

// In reducer
case 'TIMER_UPDATED':
  const duration = action.payload.duration;
  return { ...state, duration };
  1. Have the corresponding "consumer" component listen to duration prop in store.
mapStateToProps(state) {
  return {
    duration: state.duration;
  }
}
  1. Every change in duration will cause the "consumer" component to re-render.
componentDidUpdate(prevProps) {
  if (prevProps.duration !== this.props.duration) {
    // do something
  }
}

or pass duration to child

render() {
  const { duration } = this.props;
  return <SomeItem duration={duration} />;
}

Upvotes: 1

Related Questions