[Suggestion]: Make useEffectEvent be usable by default in the challenges or add a new note for useRef's alternative
まだ誰も着手していません。
- 主要言語
- JavaScript
- スター
- 11.8k
- フォーク
- 7.9k
- 平均マージ
- 1日 11時間
- マージ済み PR(30日)
- 11
説明
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.
コントリビューションガイド
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
調査の方向性
Separating Events from Effects ページから始め、ドキュメント化されている useEffectEvent の import を使って最初の challenge を再現します。challenge 環境でその API をサポートすべきか、それともページで useRef の代替案を説明すべきかを判断します。選択したアプローチが challenge とその周辺のガイダンスで利用可能になっているか、明確に説明されていれば完了です。
索引モデルが issue の本文から書いたものです。
評価
- 技術スタック
- javascript, react
- 領域
- documentation
- issue の種類
- ドキュメント
- 難易度
- 4/5
- 見積もり時間
- 3〜5日
- 活発さ
- 停滞
- 明瞭さ
- おおむね明確
- 初心者へのやさしさ
- 38/100