Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
AbdiHaryadi opened this issue Feb 15, 2025 · 0 comments

Comments

@AbdiHaryadi
Copy link

AbdiHaryadi commented Feb 15, 2025

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.

@AbdiHaryadi AbdiHaryadi changed the title [Suggestion]: Make useEffectEvent be usable by default in the challenges or add new section for useRef's alternative [Suggestion]: Make useEffectEvent be usable by default in the challenges or add a new note for useRef's alternative Feb 15, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant