Reactの難しいところは、一言でいうと「レンダリング」だと思います。
詳しい仕組みを理解しているわけではありませんが、Reactでは不要な処理を削減し、変更があった場所だけを表示し直すようにしています。
コンポーネントを組み合わせてできたページを最初に表示する作業を「レンダリング」といい、変更があった場所を更新して再表示する作業を「再レンダリング」といいます。変更があったコンポーネントだけを再レンダリングすることで、高速な処理を実現しているのだそうです。
レンダリングとは
「レンダリング」というのは、関数(=コンポーネント)を実行するということです。
const Example = () => {
let a = 1;
let b = 2;
const increment = () => {
a = a + 1;
}
return (
<div>
<h1>{ a+b }</h1>
<button onClick={ increment }>+</button>
</div>
);
}
関数コンポーネントの中では、HTML要素を返す前に、いろいろな処理を記述することができます。上のコードでは変数aとbに値を代入して、それを足したものをh1要素として表示するようにしています。ここでは「3」が表示されます。(ちなみにreturnの中の{ }はJavaScriptの「式」を記述できます。(「式」と「文」の違いもここで初めて学びました)
buttonにはクリックしたときにincrementという処理を行うように関数を渡しています。ボタンをクリックするとincrementが実行され、aの値が1増えるので、h1に表示されるのは「4」だと期待されます。しかし、残念ながらそうはなりません。
これは「レンダリング」と関係します。
試しにincrementの中にconsole.log(a)を追加してみると、確かにクリックするたびにaの値は1ずつ増えていきます。でも表示された値は変わりません。
つまり「再レンダリングされていない」ということです。
再レンダリングのきっかけ
Reactが再レンダリングするきっかけは、3つあります。
- stateが更新されたとき
- propsが更新されたとき
- 親コンポーネントが再レンダリングされたとき
今回の例では、コンポーネントを再レンダリングさせるには「state」というものを更新する必要があるということです。この「state」がReactを難しくしている一因なのではないでしょうか。
useState
コンポーネントにstate(状態?)を持たせるための関数がuseStateです。(他にもuseから始まる関数がいくつもあって、まとめてReact Hooksと呼ばれます)useStateはコンポーネントの最初の方で以下のように宣言します。
const [ number, setNumber ] = useState(1);
左辺の配列は「分割代入」というJavaScriptの記法です(この書き方もReactを学んでから覚えました)。useStateは引数を初期値とする「値」と、その値を更新するための「セッター」を配列の形で返す関数です。上の式は、useStateが返す値をnumberという変数に、セッターをsetNumberという変数に代入します。そして、
setNumber( prev => prev + 1 );
このようにsetNumberに「新しい値」を渡します。すると、Reactは「新しい値」を元に再レンダリングしてくれます。ちなみに、渡しているのはコールバック関数で、
prev => prev + 1
は
function (prev) {
return prev + 1;
}
と同じ意味です。(この記法はとても便利ですね)セッターには値を直接渡すこともできます。
セッターの使用上の注意
このセッターを使うにも注意が必要で
setNumber( number + 1);
setNumber( number + 1);
このように書くと意図した挙動となりません。一見setNumberを2回呼び出しているのでnumberの値は+2となりそうですが、結果は+1となります。これは、numberの値が更新されるのは再レンダリングのときだからです。レンダリング前のnumberの値を引数として渡しているので、結局同じ値を2回セットしたことになってしまうのです。
setNumber( prev => prev + 1 );
setNumber( prev => prev + 1 );
このように書けば、prev(更新前の値)+1を新しい値として更新し、さらにprev(1回更新後の値)+1を新しい値として更新しますので、期待通り+2されます。
こんな感じで、単に+1したいだけなのに、処理がいろいろと必要なわけです。さらに計算結果が表示されるかは「レンダリング」にかかっているので、いつレンダリングされるのかを把握していないと、期待通りの表示になりません。これがReactの難しいところではないかなと思います。
コメント