web-dev-qa-db-ja.com

Reactナビゲーションdidfocusイベントリスナーは、クラスコンポーネントと機能コンポーネントの間で異なる動作をします

この画面に遷移すると、最新のデータを取得するためのAPI呼び出しが行われます。しかし、それがクラスバージョンでうまく機能しているときに、フックバージョンのある別のナビゲーションスタックから遷移するときに、didFocusイベントがトリガーされてAPI呼び出しがトリガーされないようです。

フックバージョンをクラスバージョンと同じ動作にするにはどうすればよいですか?

この2つのバージョンの違いは何ですか?

クラスコンポーネントバージョン

class someScreen extends Component {
    componentDidMount() {
       const {
           navigation,
       } = this.props;

       this.navFocusListener = navigation.addListener('didFocus', () => {
         // do some API calls here
         console.log("class version");
         API_CALL();
       });
    }

    componentWillUnmount() {
        this.navFocusListener.remove();
    }
}

コンソール出力

他のナビゲーションスタックからこの画面への遷移:クラスバージョン

同じスタック内の画面間の遷移:クラスバージョン

フックのバージョン

const someScreen = ({
 navigation,
}) => {
    useEffect(() => {
        const navFocusListener = navigation.addListener('didFocus', () => {
        // do some API calls here
        API_CALL();
        console.log('hooooks');
    });

    return () => {
        navFocusListener.remove();
    };
  }, []);
}

コンソール出力

他のナビゲーションスタックからこの画面への移行:コンソールには何も表示されません

同じスタック内の画面間の遷移:フック

ところで、ここに私が見つけた回避策のソリューションがあります

const someScreen = ({
 navigation,
}) => {
      useEffect(() => {
          const isFocused = navigation.isFocused();

          // manually judge if the screen is focused
          // if did, fire api call
          if (isFocused) {
             // do the same API calls here
             API_CALL();
             console.log('focused section');
          }

          const navFocusListener = navigation.addListener('didFocus', () => {
              // do some API calls here
              API_CALL();
              console.log('listener section');
          });

          return () => {
              navFocusListener.remove();
          };
      }, []);
}

コンソール出力

他のナビゲーションスタックからこの画面への移行:フォーカスセクション

同じスタック内の画面間の遷移:リスナーセクション

11
chitsutote

一貫性のない行動の根本的な原因を見つけたと思います。 useLayoutEffectと呼ばれる別のフックがあります

useLayoutEffectシグネチャはuseEffectと同じですが、すべてのDOM変更の後で同期的に起動します。これを使用して、DOMからレイアウトを読み取り、同期的に再レン​​ダリングします。ブラウザがペイントする機会がある前に、useLayoutEffect内でスケジュールされた更新は同期的にフラッシュされます。

useLayoutEffectは描画をブロックしますが、useEffectはブロックしません。これは、didFocusイベントが発生したが、タイミングを逃したためにリスナーをトリガーしなかったと私の推測を確認して説明します

私の場合は、useEffectの代わりにuseLayoutEffectを使用する必要があります

参照: https://kentcdodds.com/blog/useeffect-vs-uselayouteffecthttps://reactjs.org/docs/hooks-reference.html#uselayouteffect

3
chitsutote