React Context 和 Provider 数据未按预期传递

React Context and Provider data doesn't get passed down as expected

我正在尝试更新另一个组件正在使用的对象。

我的背景:

import React, {Component, createContext} from "react";
import jwt from 'jsonwebtoken';

const LOCAL_STORAGE_AUTH_TOKEN = 'authToken';

interface AuthenticatedUser {
    username?: string;
    guildName?: string;
    guildId?: string;
}

interface AuthContextType {
    authenticated: boolean; // to check if authenticated or not
    user: AuthenticatedUser; // store user details
    token: string; //jwt token
    refreshToken: string; //jwt refresh token
    handleAuthentication: (username: string, password: string) => Promise<void>; // handle login process
    logout: () => Promise<void>; // log out the user
}

export const AuthContext = createContext<AuthContextType>({
    authenticated: false, // to check if authenticated or not
    user: {}, // store all the user details
    token: '', // store all the user details
    refreshToken: '', //jwt refresh token
    handleAuthentication: (username: string, password: string): Promise<void> =>
        Promise.resolve(), // handle login process
    logout: (): Promise<void> => Promise.resolve(), // logout the user
});
AuthContext.displayName = 'AuthContext';

export class AuthProvider extends Component {
    state = {
        authenticated:false,
        user: {},
        token:'',
        refreshToken:''
    };
    
    constructor(props: any) {
        super(props);
        
        const token = window.localStorage.getItem(LOCAL_STORAGE_AUTH_TOKEN) || '';
        const jwtData = jwt.decode(token);
        
        let user = {};
        let authenticated = false;
        let refreshToken = '';
        if(jwtData && typeof jwtData !== 'string'){
            authenticated = true;
            user = { 
                username: jwtData.data?.username || '',
                // TODO: Add the other sources too
            }
        }
        
        this.state = {
            authenticated,
            user,
            token,
            refreshToken
        }
    }
    
    handleAuthentication = async (username: string, password: string):Promise<void> => {
        fetch(process.env.REACT_APP_API_ENDPOINT  + "users/login", {
            method:"POST",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify({username:username, password:password})
        })
            .then(response => response.json())
            .then((data) => {
                /*
                        This data is coming back correctly
                */
                const user = {
                    username: data?.user.username,
                    guildName: data?.user.guild_information[0].guildName,
                    guildId: "123123"
                }
                
                this.setState({
                    authenticated: true,
                    user: user,
                    token: data?.token,
                    refreshToken: data?.refreshToken
                })
                
                window.localStorage.setItem(LOCAL_STORAGE_AUTH_TOKEN, data?.token)
                //TODO: Also save token in localstorage
            })
            .catch((err) => {
                console.log(err)
            })
    }
    
    logout = async ():Promise<void> => {
        //TODO: Log out the current user
    }
    
    render() {
        const authProviderValue = { 
            ...this.state,
            handleAuthentication: this.handleAuthentication,
            logout: this.logout
        }
        
        return (
            <AuthContext.Provider value={authProviderValue}>
                {this.props.children}
            </AuthContext.Provider>
        )
        
    }
}

以及我使用它的 App 组件:

import React, {useContext} from "react";
import { useStyles} from "./style";
import {AuthContext, AuthProvider} from "../../context/UserContext";
import RoutesProvider from "./Routes";
import Login from "../Login";

export default function App() {
  const classes = useStyles();
  const { user } = useContext(AuthContext)
  
  return (
    <AuthProvider>
        {typeof user.username !== "undefined" ? (
          <div className={classes.content}>
            <RoutesProvider />
          </div>
        ):(
          <Login />
        )}
    </AuthProvider>
  )
}

还按照建议将 App 组件包装在 AuthProvider 中:

import React from 'react';
import ReactDOM from 'react-dom';
import App from './components/App';
import { SnackbarProvider } from 'notistack';
import { AuthProvider} from "./context/UserContext";
import './styles/index.css'

ReactDOM.render(
  <React.StrictMode>
    <AuthProvider>
      <SnackbarProvider maxSnack={3}>
        <App />
      </SnackbarProvider>
    </AuthProvider>
  </React.StrictMode>,
  document.getElementById('root')
);

如果我在 AuthContext 中更改它,它确实会采用初始值。但是更新后它不会在 App 组件中更新。我对为什么这不能按预期工作感到有点困惑。如果有人知道是什么原因造成的(或者如果我做错了)请告诉我。目前调试 5 小时...

如果我正确理解你的问题,你是在问:

“当您的 handleAuthentication 方法成功时,为什么您的用户常量不更新”

答案是因为您正在您的提供商之外初始化您的用户常量。

在 index.tsx 中使用 AuthProvider 而不是像这样的 App 组件:

<AuthProvider>
   <App />
</AuthProvider>

或者将您的上下文逻辑转移到子组件中