React 导航 didfocus 事件侦听器在类组件和功能组件之间的工作方式不同

IT技术 javascript reactjs react-native react-navigation react-hooks
2021-05-25 03:51:28

当我转换到这个屏幕时,它会调用一些 API 来获取最新的数据。但是当我从另一个带有钩子版本的导航堆栈转换时,它似乎不会触发 didFocus 事件来触发 api 调用,而它在类版本中运行良好。

如何使钩子版本具有与类版本相同的行为?

这两个版本有什么区别?

类组件版本

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();
    };
  }, []);
}

控制台输出

从其他导航堆栈过渡到此屏幕:控制台中未显示任何内容

在同一堆栈中的屏幕之间转换:hooooks

顺便说一句,这是我找到的解决方法

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();
          };
      }, []);
}

控制台输出

从其他导航堆栈过渡到此屏幕:重点部分

在同一堆栈中的屏幕之间转换:侦听器部分

1个回答

我想我找到了不一致行为的根本原因。还有一个叫做 useLayoutEffect 的钩子

useLayoutEffect 签名与 useEffect 相同,但在所有 DOM 突变后同步触发。使用它从 DOM 读取布局并同步重新渲染。在浏览器有机会绘制之前, useLayoutEffect 内计划的更新将同步刷新。

useLayoutEffect 会阻止绘画,而 useEffect 不会。这证实并解释了我的猜测 didFocus 事件已触发,但它没有触发侦听器,因为它错过了时间

所以就我而言,我必须使用 useLayoutEffect 而不是 useEffect

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