React
ライフサイクル
関数コンポーネントとして実装した関数は、レンダリング時に実行される
レンダリングのタイミングは、子コンポーネントの表示切り替えやuseStateの更新など、多義に渡るため、追跡するのが難しい
基本的には、なんかすごい回数呼ばれると捉えておくと実装しやすい
最初に表示された時
状態が更新された時
useState()のset関数により、値が変わった時
親の状態が更新された時
TODO
Propsメモ
大前提として、propsはreadonlyとして扱うこと
Propsにchildrenを含めると、子タグが書けるようになる
型はReactNode型
Hooksメモ
クラスを作らずにクラスのような機能を使うための仕組み
useState
状態を保持する箱のようなものを提供する。
更新されると、レンダリングが再実行される
厳密には、インスタンスが差し代わった時にレンダリングされる。オブジェクトを入れて、オブジェクトの中身を更新しても、レンダリングは実行されない
useRef
useStateのレンダリングされない版。
単に状態を持ちたいだけならこっちを使う。useStateを使うと更新する度にレンダリングが走るため
また、input系タグのref属性に代入する事で、値の取得が行える
useMemo
関数の実行結果を保持する。
useRefに似ているが、実行タイミングが異なる。
更新の可否、と捉えると良いかもしれない。useRefの場合は、任意のタイミングで更新出来るが、useMemoの更新タイミングは、依存変数が変わったタイミング(useEffectと同じ原理)に束縛される
例えば、const a = useMemo(()=>"hoge", [])とすると、1度しか実行されない(値の更新がされなくなる)
useEffect
副作用フック
イベントハンドラ(のようなもの)
第2引数に入れたuseStateの参照が更新されると、第1引数のメソッドが実行される
第2引数に[]を入れることで、初めてレンダリングされた時のみ動作する
strictモードをonにすると、デバッグ環境で2回走るが、リリース環境では1回しか走らないので問題ない。らしい。
ただし、2回走っても問題ないよう実装することが推奨される
レンダリング時に動作すると困るような、重い処理(WebAPIを叩くなど)を書く箱
戻り値に関数を渡すことで、アンマウント時(コンポーネントが撤去された時)に動作する関数を定義できる
useCallback
関数のメモ化を行う
関数コンポーネントの中でラムダ式なんかを使って、コールバック関数を定義する・・・というのをよくやるが、この時、普通に書くとレンダリングの度に関数を生成している(メモリに書き込んでる)
そこで、useEffectの要領で利用するクロージャを指定して、関数をメモ化するフックがこれ
code:js
// ボタンを押す度に関数callbackが生成されている
let prevFunction
export const Sample = (prop) => {
const countUp = ()=>{setCount(count+1)}
const callback = ()=>{}
console.log(prevFunction === callback) // 常にfalse
prevFunction = callback
return (<Button onPress={countUp}>Count:{count}</Button>)
}
ただし、カスタムHooksで利用すると、Hook利用者が、取得した関数が更新しうるものかどうかをいちいち意識する必要が出てしまうので、関数をuseStateにつっこむとか、関数のインスタンスが変わってしまう事に不都合が起きる場合にだけ利用する方が良いかもしれない
code:js
const useMyHook = (contentId)=>{
const invokeSomething = useCallback(()=>{
if(contentId) doSomething(contentId)
else console.log("contentId not exists")
return {invokeSomething} // 1. contentIdが変われば、関数インスタンスも変わるが・・・
}
const HookUserComponent = ()=>{
const contentId = useFeatchContentIdMock()
const {invokeSomething} = useMyHook(contentId)
const onPress = useCallback(()=>{
invokeSomething() // 3. contentIdがフェッチされてもnot existsになる
}, []) // 2. useMyHookの利用者はcontentIdが変わったらinvokeSomethingが変わる事に気づけない
return (<Button onPress={onPress}>...<>)
}
画面遷移
react単体では、画面構築までしかサポートしない。そのため、画面遷移用のパッケージを別途導入する必要がある
考えようによっては、クラシックな・・・HTMLを返すタイプのサーバでも、Reactを使うって筋がありうるかも
Pathをベースにした画面遷移機構
リストのレンダリング
keyについて
key をどこから得るのか
データソースの種類によって key を得る方法は異なります。
データベースからのデータ: データがデータベースから来る場合、データベースのキーや ID は必然的に一意ですので、それを利用できます。
ローカルで生成されたデータ: データがローカルで生成されて保持される場合(例:ノートを取るアプリにおけるノート)は、アイテムを作成する際に、インクリメンタルなカウンタや crypto.randomUUID()、または uuid などのパッケージを使用します。
Reactフレームワーク
画面遷移や、データフェッチなど、素のReactは持っていないが、アプリを構築する上で必要な機能がパッケージングされたもの
react-router-domを使うパターン
TODO
用語メモ
コンポーネント
DOM(JSM?)を返す関数。レンダリングの度に何度も実行される
useEffect
副作用を表現する
マウントした時(初めてレンダリングされた時)にだけ実行される
また、第2引数に入れた状態が変化すると、副作用が再実行される
戻り値は、アンマウントされた時に実行される関数を返すことになる
useState
状態を表現する
プラグイン
Reactで、データフェッチ(表示データをWebAPIから持ってくる)する際のベストプラクティス
Reactの世界観内では、多重フェッチになるのを許容する
それが嫌なら、Reactフレームワークやライブラリを使って、レスポンスをキャッシュせよ。とのこと