なぜ反応18あなたのアプリを破損


もうだめだyour React 18 upgrade , そして、いくつかの軽いQAテストの後、何も見つけません.「簡単なアップグレード」と思う.
残念なことに、道を下って、あなたはそれがあなたの負債のフックのように聞こえるように他の開発者からのいくつかの内部のバグレポートを受け取る権利は正常に動作しません.あなたは最小限の再生を行い、フックのデモを作成することを決定.
あなたは待っている2番目の後に“警告”ダイアログをスローすると予想しますが、奇妙に、ダイアログは全く実行されません.

See and run the related code sample in the sandbox


これはあなたのマシンでちょうど先週働いていたので、これは奇妙です!なぜ、これは起こりましたか?何が変わったのか
あなたのアプリが反応18で壊れた理由は、あなたが使用していることですStrictMode .
単にあなたのindex.js (or index.ts ) ファイルを変更します.
render(
  <StrictMode>
    <App />
  </StrictMode>
);
以下のように読みます.
render(
    <App />
);
一見反応18であなたのアプリケーション内で導入されたバグのすべてが突然行っている.
つだけ問題:これらのバグは本物であり、反応18前にあなたのコードベースに存在していた-あなたはそれを実現していない.

壊れたコンポーネントの証明


以前からの例を見て、我々は使用しているReact 18’s createRoot API 与えるApp インサイドオブStrictMode 56 - 60行のラッパー.

See and run the related code sample in the sandbox


現在、ボタンを押すと、何もしない.しかし、あなたがStrictMode ページをリロードすると、Alert 討論されて2番目の後.
コードを見てみましょうconsole.log sに我々useDebounce , それ以来、私たちの関数が呼ばれることになっています.
function useDebounce(cb, delay) {
  const inputsRef = React.useRef({ cb, delay });
  const isMounted = useIsMounted();
  React.useEffect(() => {
    inputsRef.current = { cb, delay };
  });
  return React.useCallback(
    _.debounce((...args) => {
        console.log("Before function is called", {inputsRef, delay, isMounted: isMounted()});
          if (inputsRef.current.delay === delay && isMounted())
                      console.log("After function is called");
                  inputsRef.current.cb(...args);
        }, delay),
    [delay]
  );
}
Before function is called Object { inputsRef: {…}, delay: 1000, isMounted: false }

ああ!どうやらisMounted がtrueに設定されていないため、inputsRef.current コールバックは呼び出されていません:それは我々が議論される我々の機能です.
を見てみましょうuseIsMounted() コードベース:
function useIsMounted() {
  const isMountedRef = React.useRef(true);
  React.useEffect(() => {
    return () => {
          isMountedRef.current = false;
    };
  }, []);
  return () => isMountedRef.current;
}
このコードは一見して意味をなす.結局のところ、我々はuseEffect 最初にそれを削除するには、useRef 's初期セッターは、各々の表示の始まりで走ります?
まあ、かなり.

何が反応18で変更?


以前のバージョンのReactionでは、コンポーネントを一度マウントすることになります.その結果、useRef and useState 彼らが一度セットされたかのようにほとんど扱われることができて、そして、忘れられて.
反応18では、反応の開発チームは、この行動を変更することを決めたre-mount each component more than once in strict mode . 潜在的将来の反応機能が正確にその行動を持つという事実のため、これは強い部分です.
参照してください、1つの機能のチームは、将来のリリースでは、コンセプトを利用して追加することを望んでいるreusable state ”. 再利用可能な状態の背後にある一般的な考えは、あなたがunmountしているタブ(ユーザがタブを離れたときに言う)を持っているならば、再マウントされます(ユーザが戻るとき)、反応は、そのタブ・コンポーネントに割り当てられたデータを回復するでしょう.このデータをすぐに使用すると、すぐに躊躇せずに、各コンポーネントをレンダリングすることができます.
これのために、データの間、言う、useState が持続されることがあります.To quote the React docs :

This feature will give React better performance out-of-the-box but requires components to be resilient to effects being mounted and destroyed multiple times.


しかし、反応モード18内の厳格なモードでは、この行動のシフトだけでは、反応チームから保護将来の証明ではありません:それはまた、反応のルールに従って適切に、あなたの行動をクリーンアップするためにリマインダーです.
結局のところReact team themselves have been warning that an empty dependent array ( [] 2番目の引数として、それは、現在、年齢について一度だけ動くと保証してはいけません.
実際には、この記事は少し悪質かもしれません-the React team says they’ve upgraded thousands of components in Facebook’s core codebase without significant issues . 可能性が高い以上、アプリケーションの大半は、任意の問題なしに反応の最新バージョンにアップグレードすることができます.
すべては、これらの反応の誤解は、我々のアプリケーションに関係なく、自分の道クロール.反応チームが多くの破壊的なアプリを予想しないかもしれない間、これらのエラーは説明を正当化するのに比較的共通であるようです.

再実装バグを修正する方法


私が以前にリンクしたコードは、プロダクションアプリケーションで私によって書かれました.頼る代わりにuseRef 一度値を初期化するには、初期化をuseEffect .
function useIsMounted() {
  const isMountedRef = React.useRef(true);
  React.useEffect(() => {
  isMountedRef.current = true; // Added this line  
  return () => {
      isMountedRef.current = false;
    };
  }, []);
  return () => isMountedRef.current;
}
これは逆の場合も同様です!前に忘れていたかもしれないどんなコンポーネントでもクリーンアップを実行するようにする必要があります.
多くは、この規則を無視しますApp そして、他のルート要素は再マウントするつもりはありませんが、新しい厳格なモード動作では、保証はもはや安全な賭けではありません.
あなたのアプリケーション間でこのアプリケーションを解決するには、次の兆候を探します
  • クリーンアップによる副作用
  • 適切な浄化のない副作用
  • 活用[] インuseMemo and useEffect このコードが一度だけ実行されると仮定するには
  • つは、このコードを削除すると、完全に機能するアプリケーションに戻る必要がありますし、再利用することができますあなたのアプリケーションでStrictMode!

    結論


    18のようなテーブルに多くの素晴らしい機能をもたらすnew suspense features , the new useId hook , automatic batching , など.これらの機能をサポートするリファクタの仕事は、時にイライラすることがありますが、それは彼らがユーザーに現実世界の利益を提供することを覚えておくことが重要です.
    例えば、反応18は、急速なユーザー入力が処理される必要があるとき、非常により良い経験をつくるために、レンダリング業者を討議する若干の機能性も導入します.
    反応18のアップグレードプロセスの詳細については、見てくださいour instruction guide on how to upgrade to React 18