reactjs / reactjs/react.dev

[Suggestion]: Make useEffectEvent be usable by default in the challenges or add a new note for useRef's alternative

Open
#7,605 0 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

type: documentation
Dominant language
JavaScript
Stars
11.8k
Forks
7.9k
Avg merge
1d 11h
Merged PRs (30d)
11

Description

Summary

Make useEffectEvent be usable by default in Separating Events from Effects' challenges, or add a new note for useRef's alternative.

Page

https://react.dev/learn/separating-events-from-effects

Details

I attempted to solve the first challenge in Separating Events from Effects with useEffectEvent. First, following the previous example, I imported that function with this line:

import { experimental_useEffectEvent as useEffectEvent } from 'react';

Then, I used it with these lines:

const updateCount = useEffectEvent(() => {
  setCount(c => c + increment);
});

However, this error was shown up:

Runtime Error

App.js: _react.experimental_useEffectEvent is not a function (8:37)

   5 |   const [count, setCount] = useState(0);
   6 |   const [increment, setIncrement] = useState(1);
   7 | 
>  8 |   const updateCount = useEffectEvent(() => {
                                            ^
   9 |     setCount(c => c + increment);
  10 |   });
  11 | 

Therefore, by default, I can't use useEffectEvent for that exercise. I wrote "by default" because maybe it can be used by opening it in CodeSandbox. It looks like an extra effort for me, so I haven't tried it yet.

One of the solution I found for this challenge is using useRef. I think, the key for this challenge is how to avoid passing reactive elements to the Effect. Because useRef somehow can be treated as local variable which can be changed outside of render, and the interval itself is in-between render, I think it's safe to use. I need to make a Ref consistent with increment state. So, I modified each callback function of the increment buttons.

Here is my solution:

import { useState, useEffect, useRef } from 'react';

export default function Timer() {
  const [count, setCount] = useState(0);
  const [increment, setIncrement] = useState(1);
  const incrementRef = useRef(1);

  function decreaseIncrement() {
    const prevIncrement = increment;
    const newIncrement = prevIncrement - 1;
    setIncrement(newIncrement);
    incrementRef.current = newIncrement;
  }

  function increaseIncrement() {
    const prevIncrement = increment;
    const newIncrement = prevIncrement + 1;
    setIncrement(newIncrement);
    incrementRef.current = newIncrement;
  }

  useEffect(() => {
    const id = setInterval(() => {
      const localIncrement = incrementRef.current;
      setCount(c => c + localIncrement);
    }, 1000);
    return () => {
      clearInterval(id);
    };
  }, []);

  return (
    <>
      <h1>
        Counter: {count}
        <button onClick={() => setCount(0)}>Reset</button>
      </h1>
      <hr />
      <p>
        Every second, increment by:
        <button disabled={increment === 0} onClick={() => {
          decreaseIncrement()
        }}>–</button>
        <b>{increment}</b>
        <button onClick={() => {
          increaseIncrement();
        }}>+</button>
      </p>
    </>
  );
}

It would be better if the useRef's alternative is included as a new note in Separating Events from Effects section.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the Separating Events from Effects page and reproduce the first challenge using the documented useEffectEvent import. Determine whether the challenge environment should support that API or whether the page should document the useRef alternative; done means the chosen approach is available or clearly explained in the challenge and its surrounding guidance.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, react
Domain
documentation
Issue type
Documentation
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.