疲労して無の一日を過ごす。納豆にハマって毎日食ってる。一日二食ひっぱりうどん作って食べたら気持ち悪くなった。ちょっとよくなさすぎるな。
React、useRef の使い所について。コンポーネントが依存する状態のうち、変更時に再レンダリングを発生させる必要がないものを useRef で書くことができる。
が、ある種の状態はそもそも React に持たせる必要がないので、クロージャとかクラスとか JS ネイティブな機構で状態管理したほうがいいんじゃないか。
具体的にいうと、useEffect の中でアニメーションループ書いたりしてるとき、この loop 関数が依存する情報を useRef で持ったりしても別に実害はない(useState で持つと大変なことになる):
const loopCount = useRef(0);
useEffect(()=> {
const loop = () => {
loopCount.current++;
requestAnimationFrame(loop);
}
loop()
},[])
んだけど JS の世界で完結させられるものは完結させるほうがいいかもしれない:
const closureLoop = () => {
let loopCount = 0;
return () => { loopCount++; ...}
}
useEffect(()=> {
const loop = closureLoop()
loop()
},[])
が、この loopCount を React 世界の他のロジックと共有したいってなると、useRef を使いたい気持ちが出てくるかもしれない:
const loopCount = useRef(0);
const handlePlay = () => {
if(loopCount.current > 1)
...
}
useEffect(()=> {
const loop = () => { loopCount.current++; ... }
loop()
},[])
ならまあ、hooks にするか・・・(諦め):
const useLoop = () => {
const loopCount = useRef(0);
const loop = useCallback(() => {...},[])
return {loop, loopCount}
}
でもやりようはあるんだよな:
class Animation {
loopCount = 0
...
loop() { this.loopCount++ ... }
}
export const animation = new Animation();
//---
import {animation} from ...
const handlePlay = () => {
if(animation.loopCount > 1)
...
}
useEffect(()=> {
animation.loop()
},[])
たぶんこの2つの選択肢があって、基本的には前者の React に乗っかっていくスタイルで無問題なのだけど、なんとなくある種の状態に関しては React から切り離してクラスとかクロージャで書くのがスッキリする実感がある。特に今やってる仕事みたいにCanvas とか Three.js とかでお絵かきする場合。
これってなんでなんだろうなぁ。
まず、UI は React でやるけど、そこと独立して存在できるロジックや状態に関しては React 非依存にするって住み分けは一個ありそう。そもそも React って UI ライブラリ やしな。そこで何でもやるべきではないのは考えてみれば当たり前の話か・・・
React is a JavaScript library for rendering user interfaces (UI).
お絵かき系のプログラミングがクラスっぽい記法とマッチするのはなんでやろうね。
まあ JS の場合はクラスである必要はないんだけど:
const obj = {
x : 0,
update: ()=> {...}
}
例えば10個の丸を同時に動かしたい、丸はそれぞれ位置情報を持つ、みたいな要件があった場合、「丸」ってまとまりを作ってその子供を操作するのが一番直感的な気がする:
class Circle {
pos = [0,0]
update() {...}
}
const circles = Array.from({ length: 10 }, () => new Circle());
for (const circle of circles) {
circle.update();
}
もちろんクラスもクロージャも使わずにこういうことをするのは可能(これは ECS っぽい?) けどまあ考えなしにこういうことするとヤバくなりそうというのは容易に想像付きますね:
const circlesPos = Array.from({ length: 10 }, () => [0,0]);
const update = () => {
for (const pos of circlesPos){ ... }
}
for (let i = 0; i < 10; i++) {
update();
}
まあグラフィックプログラミングって当然グラフィックする(?)主体とか対象を名指せたほうがいいわけで、その点関連するデータと関数をまとめて名指す方法としてクラスってそれなりに有用ってことなんだろう。ゲームプログミングとかも同じことが言えそう。
似たような話をしてる記事があった。これは UI の状態を React 外に持ってってるのでちょっとラディカルだが、まあ大体こういうことを言いたい。:Reactでロジックをhooksにまとめないという選択肢 - Hello Tech