1

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.

1 Answer 1

1

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} />;
}
Sign up to request clarification or add additional context in comments.

2 Comments

Is this possible to do with using only functional components (and hooks), useEffect, and useReducer, rather than redux?
yes. replace redux with how useReducer works. TimerComponent can be a functional component.

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.