返回屏幕时未在 React Native 中调用 useEffect

Posted

技术标签:

【中文标题】返回屏幕时未在 React Native 中调用 useEffect【英文标题】:useEffect not called in React Native when back to screen 【发布时间】:2020-05-27 16:36:52 【问题描述】:

你好吗。 这是这个问题的场景。 假设有 2 个屏幕可以使其变得简单。

    进入A屏。 useEffect of A screen called. 从 A 屏幕导航到 B 屏幕

    从 B 导航回 A 屏幕。 此时,useEffect 没有被调用。

    function CompanyComponent(props) 
    
       const [roleID, setRoleID] = useState(props.user.SELECTED_ROLE.id)
    
       useEffect(()=> 
    
     // this called only once when A screen(this component) loaded,  
     // but when comeback to this screen, it doesn't called
       setRoleID(props.user.SELECTED_ROLE.id)
     , [props.user])
    
    

所以再次回到A屏时A屏的更新状态保持不变(不是从道具加载)

我没有更改屏幕 B 中的 props.user。 但我认为const [roleID, setRoleID] = useState(props.user.SELECTED_ROLE.id)至少应该调用这一行。

我正在使用 redux-persist。我认为这不是问题。 对于导航,我使用这个

// to go first screen A, screen B
function navigate(routeName, params) 
    _navigator.dispatch(
        NavigationActions.navigate(
            routeName,
            params,
        )
    );

// when come back to screen A from B
function goBack() 
    _navigator.dispatch(
        NavigationActions.back()
    );

屏幕出现时我可以使用任何回调吗? 我的代码有什么问题?

谢谢

【问题讨论】:

当你回到屏幕 A 时是否更改了 props.user? useEffect 不再被调用,因为 props.user 在您的情况下保持不变...您可以在一个组件中使用多个 useEffects :) 您如何在屏幕之间导航?可以加点代码吗? 你用的是什么导航包?导航做更多的堆栈而不是卸载“后退”“页面”吗? useEffect 钩子只会在第一次渲染时触发,并且只要它的依赖数组中的值更新,所以我怀疑它不会因为没有被重新挂载而再次触发。 【参考方案1】:

当您从 A 导航到 B 时,组件 A 不会被销毁(它保留在导航堆栈中)。因此,当您返回时,代码不会再次运行。

也许是一种更好的方式来实现您想要使用导航生命周期事件(我假设您使用的是react-navigation)即订阅didFocus 事件并在组件聚焦时运行您想要的任何代码例如

const unsubscribe = props.navigation.addListener('didFocus', () => 
    console.log('focussed');
);

不要忘记在适当的时候取消订阅,例如

// sometime later perhaps when the component is unmounted call the function returned from addListener. In this case it was called unsubscribe
unsubscribe();

【讨论】:

我可以知道如何取消订阅吗? 要取消订阅,你只需要调用从addListener返回的函数。在上面的例子中,我称之为unsubscribe。我也更新了上面的答案。希望这是有道理的。 如果你使用 react-navigation 5.x 试试useFocusEffect【参考方案2】:

以下解决方案对我有用:

import React,  useEffect  from "react";
import  useIsFocused  from "@react-navigation/native";

const ExampleScreen = (props) => 
    const isFocused = useIsFocused();

    useEffect(() => 
        console.log("called");
 
        // Call only when screen open or when back on screen 
        if(isFocused) 
            getInitialData();
        
    , [props, isFocused]);

    const getInitialData = async () =>     

    return (
        ......
        ......
    )

我用过 react navigation 5+

@react-navigation/native": "5.6.1"

【讨论】:

我用过useEffect(() => if(isFocused) console.log("called"); getInitialData(); , [ isFocused]); 似乎效果更好 完美,非常智能的解决方案【参考方案3】:

当前版本的 React Navigation 提供了 useFocusEffect 钩子。见here。

【讨论】:

【参考方案4】:

React Navigation 5 提供了一个 useFocusEffect 钩子,类似于 useEffect,唯一的区别是它只在屏幕当前聚焦时运行。查看文档https://reactnavigation.org/docs/use-focus-effect

 useFocusEffect(
    useCallback(() => 
      const unsubscribe = setRoleID(props.user.SELECTED_ROLE.id)
      return () => unsubscribe()
    , [props.user])
  )

【讨论】:

sigh...每次我关闭屏幕上的对话框时,应用程序都会将此行为视为将屏幕聚焦在对话框下方。所以我的useFocusEffect() 中的setShowDialog(true) 每次我关闭对话框时都会触发

以上是关于返回屏幕时未在 React Native 中调用 useEffect的主要内容,如果未能解决你的问题,请参考以下文章

使用React Native的Firebase查询未在我的屏幕上显示(但在console.log上显示)

react native - 应用程序被杀死/未启动时未收到通知

JavaScript Array flat 函数未在 React native 中定义

Jquery datatable 在从简单的 Web 服务调用 Web 方法时未在表中显示任何数据

为啥当我使用 presentModelViewController 时未在我的 UITabBArController 中调用 viewWillAppear?

阻止用户在 React Native 中成功登录后返回登录屏幕