useEffect 清理功能在 React Native 中不起作用

Posted

技术标签:

【中文标题】useEffect 清理功能在 React Native 中不起作用【英文标题】:useEffect cleanup function not working in React Native 【发布时间】:2021-10-31 05:41:25 【问题描述】:

我正在尝试从 Expo 的 SecureStore 获取令牌,然后发送一个操作。

我正在使用 useEffect 以便在组件首次渲染时检查是否有可以使用的令牌。

useEffect(() => 
let mounted = true;

SecureStore.getItemAsync('token').then((token) =>
  token ? dispatch( type: 'signin', payload: token ) : null
);

return () => (mounted = false);
, []);

但是,我无法摆脱:

无法对未安装的组件执行 React 状态更新。这是 无操作,但它表明您的应用程序中存在内存泄漏。修理, 在 useEffect 清理中取消所有订阅和异步任务 功能

enter image description here

根据要求提供更多代码:

import React,  useReducer, createContext, useEffect  from 
'react';
import * as SecureStore from 'expo-secure-store';
import forumApi from '../api/forumApi';

export const Context = createContext();

const reducer = (state, action) => 
switch (action.type) 
case ('signup', 'signin'):
  return  ...state, token: action.payload ;
case 'error': 
  return  token: undefined, errorMessage: action.payload ;

default:
  return state;
 
;

const AuthProvider = ( children ) => 
const [state, dispatch] = useReducer(reducer, 
token: undefined,
errorMessage: '',
 );

useEffect(() => 
let mounted = true;

const runAsync = async () =>
  await SecureStore.getItemAsync('token').then((token) =>
    token ? dispatch( type: 'signin', payload: token ) : null
  );

runAsync();

return () => (mounted = false);
, []);

const signup = async (fullName, email, password, passwordConfirm) 
=> 
try 
  const res = await forumApi.post('/api/v1/users/signup', 
    fullName,
    email,
    password,
    passwordConfirm,
  );

  const  token  = res.data;
  await SecureStore.setItemAsync('token', token);
  dispatch( type: 'signup', payload: token );
 catch (err) 
  dispatch(
    type: 'error',
    payload: 'We could not register you. Please try with 
 different email.',
  );
 
 ;

 const signin = async (email, password) => 
 try 
  const res = await forumApi.post('/api/v1/users/signin', 
    email,
    password,
  );

  const  token  = res.data;
  await SecureStore.setItemAsync('token', token);
  dispatch( type: 'signin', payload: token );
 catch (err) 
  dispatch(
    type: 'error',
    payload: 'We could not log you in. Please try again.',
  );
 
 ;

const signinGoogle = async (token, fullName, email, photo) => 
try 
  const res = await forumApi.post('/api/v1/users/auth/google', 
    fullName,
    email,
    photo,
  );

  await SecureStore.setItemAsync('token', token);
  dispatch( type: 'signup', payload: token );
 catch (err) 
  dispatch(
    type: 'error',
    payload: 'We could not register you. Please try with different email.',
  );

;

return (
<Context.Provider
  value= state, signup, signin, signinGoogle, tryLocalSignin 
>
  children
</Context.Provider>
 );
 ;

export default AuthProvider;

【问题讨论】:

【参考方案1】:

@florian22 所以看起来你正在尝试更新提供者级别的状态。为了更新上下文的状态,您必须在提供者内部。 useEffect 必须在内部节点上。

查看示例:

const App = (children) => 

    useEffect(() => 
     const runAsync = async () => 
     const token = await SecureStore.getItemAsync('token');

     if(token) dispatch( type: 'signin', payload: token );
     

     runAsync();
     , []);

  return (<View>children</View>);
  

const MainApp = (children) => 

return (
<AuthProvider>
 <App>
  children
 </App>
</AuthProvider>

【讨论】:

谢谢,但同样的问题。我正在使用 then 语法,所以这就是我不等待的原因。我正在使用mounted 变量,以便我可以清除订阅和异步任务。就是这么说的,我附上了截图 @florian22 你能把你所有的代码贴在页面上吗?另外,如果您还没有看到它,请查看我的修改代码。异步运行您的方法并等待它应该会阻止它尝试更新已卸载的组件。 不幸的是,异步运行它然后等待不工作。我已经添加了上面的所有代码 @florian22 请查看更新后的代码。您只能在 AuthProvider 中更新您的状态。不能在同一级别上完成。 我明白了。我调整了代码,现在不再出现错误。谢谢!【参考方案2】:

不需要使用mounted 变量。够了

useEffect(() => 
  SecureStore.getItemAsync("token").then((token) =>
    token ? dispatch( type: "signin", payload: token ) : null
  );
, []);

【讨论】:

对,这是我最初的猜测,但 React Native 对我大喊大叫,说应该清除所有订阅和异步任务

以上是关于useEffect 清理功能在 React Native 中不起作用的主要内容,如果未能解决你的问题,请参考以下文章

socket.io useEffect 清理函数 react

react 钩子中的 useEffect 执行顺序及其内部清理逻辑是啥?

删除组件后如何清理react js中的useEffect函数

React useEffect 清理函数中的依赖没有更新

React+Typescript:修复 UseEffect Hook(回调+清理函数错误)

如何取消 useEffect 清理函数中的所有订阅和异步任务?