使用上下文和钩子更新未安装组件的状态 - 反应原生

Posted

技术标签:

【中文标题】使用上下文和钩子更新未安装组件的状态 - 反应原生【英文标题】:update state on unmonted component with context and hooks - react native 【发布时间】:2021-12-09 13:18:24 【问题描述】:

更新:我已经申请了这个post的导师,但是即使使用状态isMounteduseEffect清理功能我仍然无法解决这个问题。代码似乎运行良好,但我总是收到此警告。

我有一个应用程序组件,它通过条件渲染管理两个页面的导航,如果我已登录,则输入一个,如果我未登录,则输入另一个。

import context from "./components/context"

const Stack = createNativeStackNavigator();

export default function App() 
    const [isLoggedIn, setLoggedIn] = useState(false);

    useEffect(() => 
        let isMounted = true;

        let store = async () => 
            await SecureStore.deleteItemAsync("accessToken")
            let accessToken = await SecureStore.getItemAsync("accessToken");
            if(accessToken && isMounted) 
                setLoggedIn(true)
            
        
        store().then()

        return () => 
            isMounted = false
        
    , [])

    return (
        <>
            <NavigationContainer>
                <context.Provider value=isLoggedIn, setLoggedIn>
                    <Stack.Navigator >
                        <Stack.Screen name=isLoggedIn ? "HomePantry" : "Home" component=isLoggedIn? HomePantry : Home  />
                    </Stack.Navigator>
                </context.Provider>
            </NavigationContainer>
        </>
    );

我的档案context.js

export const context = React.createContext();

这是我的简单主页组件(在用户登录之前)。

export default function Home(navigation) 

    return (
            <View>
                <Text> My pantry </Text>
                <UserLogin />
            </View>
    );

这是UserLogin 子组件。一旦用户输入了正确的凭据,我正在使用上下文来更新isLoggedIn 状态。问题是当应用组件卸载时状态会更新,这会导致无操作。

我收到以下警告: “无法对未安装的组件执行 React 状态更新 - 内存泄漏?”

如果有人有任何想法,我还无法解决这种情况。提前致谢。

import context from "./context";

export default function UserLogin() 
    const contest = React.useContext(context)

    return (
        <View style=styles.inputsContainer>
            <Formik
                initialValues= email: '', password: '' 
                onSubmit=
                    async (values, actions) => 
                        if(values.email.trim() !== "" && values.password.trim() !== "")
                            const response = await fetch('https://lam21.iot-prism-lab.cs.unibo.it/auth/login', 
                                method: 'POST',
                                headers: 
                                    'Content-Type': 'application/json'
                                ,
                                body: JSON.stringify(
                                    email: values.email,
                                    password: values.password
                                )
                            );
                            let json = await response.json()
                            if(json.accessToken)
                                contest.setLoggedIn(true)
                                await SecureStore.setItemAsync("accessToken", json.accessToken);
                                actions.resetForm()
                             else 
                                alert("Username o password sbagliati!")
                            
                        
            >
                ( handleChange, handleBlur, handleSubmit, values ) => (
                    <View style=styles.inputsContainer>
                        <Text style=styles.labelText> Email </Text>
                        <TextInput
                            required
                            onChangeText=handleChange('email')
                            onBlur=handleBlur('email')
                            value=values.email
                            placeholder="Inserisci la tua mail.."
                            style=styles.inputText
                        />
                        <Text style=styles.labelText> Password </Text>
                        <TextInput
                            required
                            onChangeText=handleChange('password')
                            onBlur=handleBlur('password')
                            value=values.password
                            placeholder="Inserisci la tua password.."
                            style=styles.inputText
                        />
                        <View style=styles.inputButton>
                            <Button onPress=handleSubmit title="Submit" color="purple" style=styles.inputButton />
                        </View>
                    </View>
                )
            </Formik>
        </View>
    );

登录后的homepantry组件:

export default function HomePantry() 

    return (
        <View>
            <Text> My pantry </Text>
        </View>
    );

【问题讨论】:

阅读:[***.com/questions/53949393/…。 @ford04 的答案 Link 直接到ford04的回答。 不幸的是,是的,但现在我正试图通过不同的实现来避免这个问题......我仍在努力。 你好朋友,问题解决了吗? 是的,现在它可以工作了,但实现方式不同 【参考方案1】:

问题是当您在promise 上设置状态时。该组件是在 promise 解决之前挂载的,所以您只需要检查它是否仍然挂载;

useEffect(() => 
        let isMounted = true;
        let store = async () => 
            let accessToken = await SecureStore.getItemAsync("accessToken");
            if(accessToken && isMounted)
                setLoggedIn(true)
            
        
        store().then()
        return () => 
            isMounted = false;
        ;
    ,[]);

【讨论】:

我现在尝试了这个解决方案,但警告始终存在..

以上是关于使用上下文和钩子更新未安装组件的状态 - 反应原生的主要内容,如果未能解决你的问题,请参考以下文章

更新时反应钩子状态未定义

反应钩子:新状态值未反映在 setInterval 回调中

反应钩子:useState/context;无法读取未定义的属性“头像”/如何更新嵌套对象

使用 Context API 在函数组件中反应未定义的状态属性

警告:无法对未安装的组件(多个组件)执行 React 状态更新

反应钩子如何确定它们的组件?