React 导航 didfocus 事件侦听器在类组件和功能组件之间的工作方式不同 [英] React navigation didfocus event listener works differently between class component and functional component

查看:158
本文介绍了React 导航 didfocus 事件侦听器在类组件和功能组件之间的工作方式不同的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

这两个版本有什么区别?

类组件版本

class someScreen 扩展组件 {componentDidMount() {常量{导航,} = this.props;this.navFocusListener = navigation.addListener('didFocus', () => {//在这里做一些 API 调用console.log("类版本");API_CALL();});}componentWillUnmount() {this.navFocusListener.remove();}}

控制台输出

<块引用>

从其他导航堆栈过渡到此屏幕:类版本

在同一个堆栈中的屏幕之间转换:类版本

钩子版本

const someScreen = ({导航,}) =>{useEffect(() => {const navFocusListener = navigation.addListener('didFocus', () => {//在这里做一些 API 调用API_CALL();console.log('hooooks');});返回 () =>{navFocusListener.remove();};}, []);}

控制台输出

<块引用>

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

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

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

const someScreen = ({导航,}) =>{useEffect(() => {const isFocused = navigation.isFocused();//手动判断屏幕是否对焦//如果是,则触发 api 调用如果(isFocused){//在这里执行相同的 API 调用API_CALL();console.log('重点部分');}const navFocusListener = navigation.addListener('didFocus', () => {//在这里做一些 API 调用API_CALL();console.log('监听部分');});返回 () =>{navFocusListener.remove();};}, []);}

控制台输出

<块引用>

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

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

解决方案

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

<块引用>

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

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

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

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

When I transition to this screen, it will do some API calls to fetch the latest data. But it seems not trigger the didFocus event to fire the api calls when I transition from another navigation stack with hooks version while it works well with class version.

How do I make hooks version have the same behavior as class version?

What's the difference between this two version?

class component version

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

console output

transition from other navigation stack to this screen: class version

transition between screens in same stack: class version

Hooks version

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

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

console output

transition from other navigation stack to this screen: nothing is shown in console

transition between screens in same stack: hooooks

BTW, here is the workaround solution I found

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

console output

transition from other navigation stack to this screen: focused section

transition between screens in same stack: listener section

解决方案

I guess I found the root cause of the inconsistent behavior. There is another hook called useLayoutEffect

useLayoutEffect The signature is identical to useEffect, but it fires synchronously after all DOM mutations. Use this to read layout from the DOM and synchronously re-render. Updates scheduled inside useLayoutEffect will be flushed synchronously, before the browser has a chance to paint.

the useLayoutEffect will block the painting while the useEffect will not. That confirm and explains my guess that the didFocus event had fired, but it didn't trigger the listener since it miss the timing

so in my case, I have to use useLayoutEffect instead of useEffect

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

这篇关于React 导航 didfocus 事件侦听器在类组件和功能组件之间的工作方式不同的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆