为什么 useReducer 不更新 React 上下文中的状态

Why useReducer doesn't update state in React context

我正在使用 useReducer 和上下文来更新我在 App.js 中的状态,然后将数据发送到数据库,但它不会更新状态并且始终为空。

App.js

import AuthContext from './context';
import screenA from './screenA';

export default function App() {

 const initialLoginState = {
   email: null,
 };
const loginReducer = (prevState, action) => {
   switch (action.type) {
     case 'Email':
       return {
         ...prevState,
         email: action.Email,
       };
   }
 };

const authContext = React.useMemo(
   () => ({
     email: emailUser => {
       dispatch({type: 'Email', Email: emailUser});
       console.log(loginState.email);
     },
     signIn: async () => {
       try {
         fetch('FakeApi', {
           method: 'POST',
           headers: {
             Accept: 'application/json',
             'Content-Type': 'application/json',
           },
           body: JSON.stringify({
             email: loginState.email,
             date: '2021-9-20',
           }),
         });
       } catch (e) {
         console.log(e);
       }
     },
   }),
   [],
 );
 const [loginState, dispatch] = React.useReducer(
   loginReducer,
   initialLoginState,
 );

return (
   <AuthContext.Provider value={authContext}>
         <screenA />
   </AuthContext.Provider>

Blockquote context

我创建了一个单独的上下文组件

context.js

import React from 'react';

export const AuthContext = React.createContext();

Blockquote screenA

在 screenA 中,我使用电子邮件和登录将数据发送到 App.js,然后将这些数据保存在数据库中 screenA.js

import {AuthContext} from './context';

function screenA() {
 const {email,signIn} = React.useContext(AuthContext);
 return (
   <View style={{marginTop: 150}}>
     {/* Count: {state.count} */}
     <Button
       title="sent email"
       onPress={() => {
         email('example@gmail.com');
       }}
     />
     <Button
       title="signIn"
       onPress={() => {
         signIn();
       }}
     />
   </View>
 );
}

export default screenA;

需要注意的几点:

  1. reducer 应该总是 return 状态对象(将 default case 添加到 switch)
  2. 最好在action中传一个叫payload的属性,以免出错
  3. 提供者需要一个对象value(添加另一组{})

尝试像这样更改您的代码:

const loginReducer = (prevState, action) => {
   switch (action.type) {
     case 'Email':
       return {
         ...prevState,
         email: action.payload,
       };
       default:
           return prevState
   }
 };

const authContext = React.useMemo(
   () => ({
     email: emailUser => {
       dispatch({type: 'Email', payload: emailUser});
       console.log(loginState.email);
     },
     ...
   }),
   [],
 );

return (
   <AuthContext.Provider value={{authContext}}>
         <screenA />
   </AuthContext.Provider>

正在更新状态,问题是您试图在“调度”后立即将值写入控制台,而此时状态尚未更新。如果要查看更新后的值,将这个useEffect添加到App.js

  useEffect(() => {
    console.log(loginState.email);
  }, [loginState.email]);

这个useEffect会在“loginState.email”变化时触发。

您应该考虑使用 React Developer Tools 来验证状态更改。