React state hookを深く理解する


まず問題を見てください.下のコンポーネントの中で3回のコンポーネントCounterの「set Counter」ボタンを押すと、コンソール出力は何ですか?
function Display({ counter }) {
    console.log('Display.render', counter);
    return 

{counter}

} function Counter() { const [counter, setCounter] = useState(1); console.log('Counter.render', counter); return ( <> > ) }
正しい答え:
  • は初めて「set Counter」ボタンをクリックし、stateは2になり、一回のre-renderをトリガします.出力:
    Counter.render 2
    Display.render 2
  • は「set Counter」ボタンを二回クリックしました.stateは変化していませんが、もう一回のコンポーネントCounter re-renderをトリガしました.しかし、トリガコンポーネントDisplay re-renderがありません.出力:
    Counter.render 2
    Display.render 2
    Counter.render 2
  • 第3回「set Counter」ボタンをクリックしたが、stateは変更されておらず、re-renderもトリガされていない.
  • 正解したら、直接に賞賛して前のページに戻ることができます.正解がないと残りの内容を読む時間がかかります.
    一、キューの更新
    実は、各state Hookは更新待ち行列に関連しています.setState関数を呼び出すたびに、Reactは更新関数をすぐに実行するのではなく、更新関数を更新キューに挿入し、Reactはre-renderを配置する必要があるとReactに教えます.
    function Counter() {
        const [counter, setCounter] = useState(0);
        console.log('Counter.render', counter);
        return (
               <>
                   
                   
                   
               >
       )
    }
    まず「Add」ボタンを押してから「set Counter」ボタンをクリックして出力を見てください.
    Click event begin
    Click event end
    update 1
    update 2
    Counter.render 2
    Display.render 2
    イベントハンドラを実行中に更新関数は実行されませんでした.主に性能の最適化のために、複数のsetState関数がコールされる可能性があるからです.
    1.2複数のジョブキュー
    各state Hookは、タスク・キューに対応しており、1つのコンポーネントには複数のタスク・キューが含まれる可能性がある.
  • 各タスク・キューは互いに独立している.
  • 各ジョブキューの更新関数の実行順序は、ジョブキューの作成順序、すなわちuseStateを呼び出す順序に依存する.
  • function Counter() {
        console.log('Counter.render begin');
        const [counter, setCounter] = useState(1);
        const [counter2, setCounter2] = useState(1);
        return (
               <>
                   

    counter1: {counter}

    counter2: {counter2}

    > ) }
    setCounterに対応するジョブキューの更新関数は、setCounter2に対応するジョブキューの更新関数よりも常に先行して実行される.
    二、不精計算stateが必要なときだけ、Reactは最新のstate値を計算します.つまり、useStateが再実行されるまで更新キューの更新関数が実行されます.また、同じ更新キューの複数の更新関数は順次実行され、前の更新関数の出力は次の更新関数の入力として使用されます.
    function Display({ counter }) {
        console.log('Display.render', counter);
        return 

    {counter}

    } function Counter() { console.log('Counter.render begin'); const [counter, setCounter] = useState(0); console.log('Counter.render', counter); return ( <> > ) }
    まず「Add」ボタンを押してから「set Counter」ボタンをクリックして出力を見てください.
    Click event begin
    Click event end
    Counter.render begin
    update 1, prev=1
    update 2, prev=10
    Counter.render 20
    Display.render 20
    この時先に実行されたレンダリング関数を発見し、更新関数を実行します.二番目の更新関数の参照は、最初の更新関数の戻り値です.
    三、バッチ処理useStateを再実行した場合にのみ、更新関数が実行され、すなわちレンダリング関数が再実行された場合にのみ、stateに変化があるかどうかが分かる.Reactはいつまたレンダリング関数を実行しますか?一般的には、イベント処理関数(ユーザインタラクション、ネットワーク)でsetStateを呼び出し、Reactはバッチ処理でコールバック関数を実行します.コールバック関数が実行された後、re-renderの要求がトリガされると、Reactはre-renderをトリガする.
  • バッチ処理は、最大一回のre−renderをトリガし、一つのバッチ処理には複数のタスクキューが含まれてもよい.
    function Counter() {
        console.log('Counter.render begin');
        const [counter1, setCounter1] = useState(0);
        const [counter2, setCounter2] = useState(0);
    
        return (
               <>
                   

    counter1={counter1}

    counter2={counter2}

    > ) }
    「set Counter」ボタンをクリックして、出力を見てください.
    Counter.render begin
  • バッチの処理は、コールバック関数内の同期コードしか処理できません.非同期コードは新しいバッチとして処理されます.
    function Display({ counter }) {
        console.log('Display.render', counter);
        return 

    {counter}

    } function Counter() { console.log('Counter.render begin'); const [counter, setCounter] = useState(0); return ( <> > ) }
    は「set Counter」ボタンをクリックして、出力を見てください.
    Counter.render begin
    Display.render 10
    Counter.render begin
    Display.render 20
    は2回のバッチ処理をトリガします.
  • 四、レンダリングをスキップするstateの値が変化していないと、Reactはコンポーネントを再レンダリングしないことを知っています.しかし、上からReactはuseStateを再実行する時だけstateの値を計算すると分かりました.最新のstateを計算するためにre-renderをトリガする必要がありますが、stateは不変でレンダリングコンポーネントがない場合、卵があるかそれとも先に鶏があるかのようです.Reactは2つのポリシーでスキップして再レンダリングします.
    4.1直ちに計算する
    上に述べたのはすべて怠惰な計算です.実はReactはすぐに計算しています.Reactは直ちに関数を更新します.
  • state値が不変であれば、re-renderをトリガしない.
  • state値が変化したら、怠け者ローディングポリシーに移行する.
  • 前回の計算のstateが変化していないか、または前回のstateである場合は、すぐに実行されるポリシーを用いて更新関数を呼び出す.
  • 現在stateは初期stateである.
    function Counter() {
        console.log('Counter.render begin');
        const [counter, setCounter] = useState(1);
        return (
               <>
                   

    counter={counter}

    > ) }
    は「set Counter」ボタンをクリックして出力を見てください.
    Click event begin
    update
    Click event end
    はReactデフォルトは即時実行ポリシーを採用すると説明しています.
  • 前回の計算state不変
    function Counter() {
        console.log('Counter.render begin');
        const [counter, setCounter] = useState(1);
        return (
               <>
                   

    counter={counter}

    > ) }
    は2回以上の「set Counter 2」ボタンをクリックして(前回の計算結果を作成するのはstateです.)、もう一度「set Counter」ボタンをクリックして出力を見てください.
  • 4.2怠惰計算
    不精計算とは上記の通りです.怠惰な計算中に最終的に計算されたstateに変化が発見されなかった場合、Reactはコンポーネントのサブコンポーネントを選択しない、すなわちこのときはコンポーネントレンダリング関数が実行されたが、コンポーネントのサブコンポーネントはレンダリングされない.
    function Display({ counter }) {
        console.log('Display.render', counter);
        return 

    {counter}

    } function Counter() { console.log('Counter.render begin'); const [counter, setCounter] = useState(1); return ( <> > ) }
    「set Counter 2」ボタンを二回クリックして、出力を見てください.
    Counter.render begin
    Display.render 2
    Counter.render begin
    第2のクリックは、親コンポーネントre-renderをトリガしたが、サブアセンブリDisplayre-renderを有しない.
    不精計算による問題は、一次構成要素re-renderを多くトリガするだけであるが、これは一般的に問題ではない.React useState APIドキュメントも言及しました.
    Note that React may still need to render that specific component again before bailing out.That shout't be a concern because React won't unnecessary go“deeper”into the tree.If you’extringtivent.
    4.3直ちに自動転怠計算を計算する
    1つのバッチ処理において、直ちに計算してstateが変化すると、すぐに怠惰計算モードになります.つまり、後のすべてのジョブキューの更新関数は実行されません.
    function Counter() {
        console.log('Counter.render begin');
        const [counter, setCounter] = useState(1);
        return (
               <>
                   

    counter={counter}

    > ) }
    「set Counter」ボタンをクリックして、出力を見てください.
    Click event begin //          
    update 1 //   state   state,        ,          1
    update 2 //     1     state,          ,          2,  state     ,      
    Click event end
    Counter.render begin
    update 3
    2を実行した後にstateが変化しました.Reactは直ちに怠惰負荷モードになりました.後の更新関数はすぐに実行されなくなりました.
    参照
    gitHubからノートを整理する:
  • 解読React state hook
  • State Hook