I am trying to update an object that another component is using.
My Context:
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>
)
}
}
And the App component where I use it:
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>
)
}
Also wrapped the App component within the AuthProvider as recommended:
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')
);
It does take the initial value if I change it in the AuthContext. But after updating it does not update in the App component. I'm a little confused as to why this doesn't work as expected. If anyone knows what causes this (or if I'm doing it wrong) let me know please. Currently 5 hours into debugging...