ページリロードなしでルートを回復する


最近、私はそれが反応ルータでバグのように思えた上で働いているアプリで面白いバグに遭遇しました.私は、それが本当にバグであるというわけではありませんでした、しかし、何かが反応ルータで実装されないままになったので、それが開発者の必要に応じて複数の方法で「固定」されることができるので.( the issue on github )
私たちの特定の問題は、我々は現在の反応ルートによってレンダリングされたリストの項目を更新していたサーバーコールの後にページリフレッシュをしたいということでした.リストは、より高いコンテクスト状態に格納されたいくつかのフィルタに基づいてロードされます.さらに、我々のアプリは、ルートが特定のサブセット内に応じてマウントされていることを意味する別のアプリケーションにロードされました.
最初にページリフレッシュをしなければならなかったコードは
handleItemUpdateSuccess() {
  history.push('app/list');
}
ここで問題となるのは、反応がapp/list 国家では何も変わっていなかったからです.

ステップ1
私が考えていた最初の解決策はdispatch the getList アクションとリストコンポーネントの読み込み自体は、何もしないでください.これは正しい解決策であったかもしれませんが、私のリストコンポーネントに非常に特有のようでした.
それから、私は我々のスタンドアロンアプリケーションの中でちょうどうまく働いたハックを見つけました.
handleItemUpdateSuccess() {
  history.push('/');
  history.replace(redirectPath);
}

ステップ2
しかし、アプリケーションのルータがネストされたルートにマウントされたのでhistory.push('/') 国連は、そこにロードされた反応アプリ全体をマウントします.これは、コンテキスト全体がワイプされることを意味します.
次のステップは、マイクロフロントアプリのインデックスルートにプッシュすることでした.

  history.push(MicroFrontendRoute.Index);
  history.replace(redirectPath);
これは1つの問題を解決します.

ステップ△3-溶液
現在、問題は、これがいつも正しく作動していないということです.どのように高速(または遅い)に応じて反応ルーターは、それがコンポーネントをマウントしないかをトリガする管理場所を更新!それで、2番目の歴史アップデートが遅れているならば、少しの反応はそれがそうであることを示します.
使用に苦労した後setTimeout JSメソッドと適切に行うことができるbeeingclearTimeout 同じ方法で、カスタムフックにすべてを抽出することにしました.
# ../app/routes/useRefresh.ts
import { useEffect } from 'react';

import { MyAppRoute } from './MyAppRoute';

export default function useRefresh(history: any, path: string, resetRoute: string = MyAppRoute.Index) {
  let handler: any;

  const refresh = () => {
    history.push(resetRoute);

    handler = setTimeout(() => history.push(path), 10);
  };

  useEffect(() => {
    return () => handler && clearTimeout(handler);
  }, [handler]);

  return refresh;
}
今、すべてのリフレッシュロジックが安全に独自のフックにカプセル化されているので、それをどのように使うのが簡単かを教えてください.
  const history = useHistory();
  const refresh = useRefresh(history, redirectPath);

  const handleSuccess = () => {
    if (history.location.pathname === redirectPath) {
      refresh();
    } else {
      history.push(redirectPath);
    }
  };

  const handleErrors = () => {
    ...

余震
私が上記のコードスニペットを貼ったので、私は私のuserefreshフックAPIをさらに簡単にすることができると思い始めています.パラメータはありません:
  • 方法についてuseHistory インサイドフック-第1パラメータダウン
  • redirectPath 返されるより多くに合うようですrefresh 関数-- 2番目のパラメータもダウンします.
  • リファクタリングを行います.

    ボーナス
    ここではいくつかのユニットテスト私はuseRefresh Jestとテストライブラリを使用してフック..
    import { renderHook, act } from '@testing-library/react-hooks';
    import { createMemoryHistory } from 'history';
    
    import useRefresh from '../../../../components/app/routes/useRefresh';
    import { MyAppRoute } from '../../../../components/app/routes/MyAppRoute';
    
    describe('useRefresh', () => {
      const history = createMemoryHistory();
      const subject = () => renderHook(() => useRefresh(history, MyAppRoute.List));
    
      it('returns a function', () => {
        const { result } = subject();
    
        expect(typeof result.current).toBe('function');
      });
    
      it('redirect to the Index route and then back to the given path', async () => {
        jest.useFakeTimers();
        jest.spyOn(history, 'push');
    
        const { result } = subject();
    
        result.current();
    
        expect(history.push).toHaveBeenCalledWith(MyAppRoute.Index);
    
        act(() => {
          jest.runAllTimers();
        });
    
        expect(history.push).toHaveBeenCalledWith(MyAppRoute.List);
        expect(history.push).toHaveBeenCalledTimes(2);
      });
    
      it('clears the timeout', () => {
        jest.useFakeTimers();
    
        const { result, unmount } = subject();
    
        result.current();
    
        act(() => {
          jest.runAllTimers();
        });
    
        unmount();
        expect(clearTimeout).toHaveBeenCalledTimes(1);
      });
    });
    
    あなたが反応ルータとルートをリフレッシュするより良い方法を知っているならばsetTimeout :| コメントで知らせてください