React 导航 didfocus 事件侦听器在类组件和功能组件之间的工作方式不同 [英] React navigation didfocus event listener works differently between class component and functional component
问题描述
当我转换到这个屏幕时,它会调用一些 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-uselayouteffect一>https://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屋!