React 18での相違点


2022年3月8日にリリースされたRelease Candidate.
あと少しで、正式にリリースされたreact v 18を使用することができます.
react v 17は2020年10月にリリースされたが、機能は追加されていない.

Concurrent Rendering


JavaScriptは、単一スレッドベースの言語です.一度に一つのことしか処理できない.
したがってjavascriptでは,タスクが割り当てられ,優先度に従って順番にタスクが実行される.
並列処理の概念とは異なる.実際、タスクは同時に処理されるのではなく、迅速に交互に処理されるので、同時に実行されるように見えます.
Concurrent Renderingは、SuspenceやStartTransition()、UserDeferredValue(API)など多くの新機能をサポートするバックグラウンドプッシュです.これによって得られるのは、ユーザーに優しいUI更新です.

Suspense


以前は、データをクエリーし、クエリーのステータスを使用して条件付きレンダリングを行いました.
UI要素は常にクエリの状態に依存します.
Suspenceを使用すると、これらのUI要素がクエリーのステータスへの依存を解決するのに役立ちます.
const [loading, setLoading] = useState(true);

if myData != null {
    setLoading(true); 
} 

<>
    { !loading && 
        <MyComponent />
    }
    { loading && 
        <Loading />
    }
<>
<Suspense fallback={<Loading/>}>
    <MyComponent myData={myData}/>
</Suspense> 

Automatic Batching


以前は、バッチは単一のイベントハンドラでのみ発生していました.React v 18自動バッチ処理.
// 이전에는 아래코드로 인해, 리렌더링이 각각 발생하였습니다.
fetch('http://example.com/data.json').then(() => {
    setIsLoading(false); 
    setData(data);
    setError(null);
});

function handleClick() {
    fetchSomething().then(() => {
      // React 17과 이전 버전에서는 이 업데이트들이 handleClick이 *진행되는 중*이 아닌, *완료된 후의* 콜백에서 실행되기 때문에 일괄처리 되지 않았다.
      setCount((c) => c + 1); // 리렌더링 발생
      setFlag((f) => !f); // 리렌더링을 발생
    });
}

function handleClick2() {
    setCount(c => c + 1); // 아직 렌더링 안했어요!
    setFlag(f => !f); // 아직 렌더링 안해요!!
    // React는 이 끝에서 리렌더링을 한번만 합니다. (that's batching!)
  }
これにより、上記のコードも一括処理されるため、不要なレンダリングは発生しません.

New APIs

  • useTransition()ユーザーが次の画面に移行する前に、コンポーネントが望ましくないロード状態にならないように、コンテンツのロードを待つことができます.また、遅いデータ読み込みを遅らせることで、後続のレンダリングのために、構成部品がより重要な更新をすぐにレンダリングできるようにすることもできます.
    userTransition hookは2つの配列を返します.startTransition:コールバックを受信する関数isPending:boolean値、変換完了を示す
  • 
    const SUSPENSE_CONFIG = { timeoutMs: 2000 };
    
    function App() {
      const [resource, setResource] = useState(initialResource);
      const [startTransition, isPending] = useTransition(SUSPENSE_CONFIG);
      return (
        <>
          <button
            disabled={isPending}
            onClick={() => {
              startTransition(() => {
                const nextUserId = getNextId(resource.userId);
                setResource(fetchProfileData(nextUserId));
              });
            }}
          >
            Next
          </button>
          {isPending ? " Loading..." : null}
          <Suspense fallback={<Spinner />}>
            <ProfilePage resource={resource} />
          </Suspense>
        </>
      );
    }
  • useDeferredValue()一部の更新は遅延する可能性があります.ロック解除のように使えます.
    レンダリング順序は、遅延によって制御されます.
  • const deferredValue = useDeferredValue(value, { timeoutMs: 4000 }); 
    
    return (
      <div>
        <MyComponent value={deferredValue} />
      </div>
    );

    ReactDOM.render -> ReactDOM.createRoot

    // The old way:  
    ReactDOM.render(
      <App />,
      document.getElementById('root')
    );
    
    // The new way: 
    const root = ReactDOM.createRoot(document.getElementById('root')); 
    root.render(<App/>);
    ReactDOM.render()コードは使用可能ですが、コンソールにエラーが発生し、react v 18の新しい機能は使用できません.