【问题标题】:React context api with useReducer state not changing反应上下文 api 与 useReducer 状态不改变
【发布时间】:2021-12-31 11:19:10
【问题描述】:

我有一个 Auth 屏幕和一个 HomeScreen,为了管理我正在使用的 Context API 的状态,我有 2 个状态 -> 1) user 我决定是否通过身份验证的状态(同时从服务器获取信息),2)loading 状态以在所有这些发生时显示加载屏幕。问题是,一切正常,甚至将 user 的状态从 null 设置为来自我的 API 的明确定义的对象,并且以同样的方式我正在更改我的 loading 状态但它没有改变,它是false 每次尽管我使用相同的方法进行调度。

上下文文件:

import React, { createContext, useContext, useReducer } from 'react';
import {UserReducer} from './reducers';

const initialState = {
  user: null,
  loading: false,
};

const UserContext = createContext(initialState);

export const UserProvider = ({children}) => {
  const [globalState, dispatch] = useReducer(UserReducer, initialState);

  return (
    <UserContext.Provider value={{
      user: globalState.user,
      loading: globalState.loading,
      dispatch,
    }} >
      {children}
    </UserContext.Provider>
  );
};

export default function() {
  return useContext(UserContext);
}

动作:

export const SET_USER_DETAILS = (userDetails) => {
  return {
      type: 'SET_USER_DETAILS',
      payload: userDetails,
  };
};

export const SET_LOADING = (loadingState) => {
  return {
    type: 'SET_LOADING',
    payload: loadingState,
  };
};

减速机:

export const UserReducer = (state, action) => {
  switch (action.type) {
    case 'SET_USER_DETAILS':
      return {
        ...state,
        user: action.payload,
      };
    case 'SET_LOADING':
      return {
        ...state,
        loading: action.payload,
      };
    default:
      return state;
  }
};

主导航文件:

const Navigation = () => {
  const {user, dispatch, loading} = useAuth();
  console.log(user); // after successful fetch from api, I'm getting the desired user data.
  console.log(loading); //  PROBLEM => always false.

  useEffect(() => {
    checkUserLoggedInStatus(dispatch);
  }, [dispatch]);

  return loading ? (
    <LoadingScreen />
  ) : !user ? (
    <Stack.Navigator screenOptions={{headerShown: false}}>
      <Stack.Screen name="Login" component={LoginScreen} />
      <Stack.Screen name="Register" component={RegisterScreen} />
      <Stack.Screen name="Verify" component={OTPVerificationScreen} />
    </Stack.Navigator>
  ) : (
    <Stack.Navigator>
      <Stack.Screen name="Home" component={HomeScreen} />
      <Stack.Screen name="Message" component={MessageScreen} />
    </Stack.Navigator>
  );
};

checkUserLoggedInStatus 函数:

export const checkUserLoggedInStatus = (dispatch) => {
  dispatch(SET_LOADING(true)); // NOT WORKING/NOT CHANGING THE LOADING STATE
  AsyncStorage.getItem('token')
  .then((token) => {
    if (token) {
      fetch(`${API_URL}/user/`, {
        method: 'GET',
        headers: {
          ...
        },
      })
      .then(response => response.json())
      .then((data) => {
        if (data.type === 'success') {
          const details = data.data.user;
          dispatch(SET_USER_DETAILS(details)); // THIS IS WORKING FINE.
        }
      })
      .catch((error) => {
        console.log(error.message);
      });
    }
  })
  .catch((error) => {
    console.log(error.message);
  });
  dispatch(SET_LOADING(false)); // NOT WORKING/NOT CHANGING THE LOADING STATE
};

我无法理解我做错了什么,因为我正在使用 SET_USER_DETAILS 动作/减速器功能做同样的事情,但我不知道 loading 状态有什么问题。

摘要:无法根据来自UserContextloading 状态呈现LoadingScreen

如果有人可以帮助我,我将不胜感激!

谢谢!

【问题讨论】:

  • 你可以查看这个如何使用上下文实时示例stackblitz.com/edit/…
  • 嘿,谢谢您的评论,我使用的是Context API 而不是redux,尽管样板和概念非常相似,但我知道 contextAPI 是如何工作的,因为我能够更改user 状态而不是loading 状态,即使两个函数都是使用相同的方法编写的。你有什么解决办法吗?

标签: reactjs react-native react-hooks react-context


【解决方案1】:

您的实现问题在于,在checkUserLoggedInStatus 中,您在thencatch 块之外将加载状态设置为false。由于您正在执行异步任务,并且需要在此异步任务完成后将 loading 设置为 false,因此您需要在 thencatch 中将 loading 设置为 false。

【讨论】:

  • 谢谢,成功了!还有一件事,当状态发生变化时,我可以看到我的登录屏幕有一毫秒——在控制台中出现错误,然后是加载屏幕,最后是我的身份验证屏幕。错误是:Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method. In PhoneInput (at Login/index.js:37) 可能是什么原因造成的?
猜你喜欢
  • 2021-01-17
  • 1970-01-01
  • 1970-01-01
  • 2019-03-27
  • 2020-08-08
  • 1970-01-01
  • 2020-08-01
  • 2019-07-25
  • 1970-01-01
相关资源
最近更新 更多