我试图在NextJS中为我的项目实现一个简单的登录功能,并且试图使用Context API来存储用户的数据。从后端获取数据后,我尝试更新上下文,但未更新。尝试将其记录在控制台中时,它会显示一个空对象。
这是我尝试过的:
UserContextProvider.js
import React, { useState, createContext } from 'react';
export const UserContext = createContext();
const UserContextProvider = (props) => {
const [user, setUser] = useState({ });
const storeUser = new_user => {
console.log("User: ", new_user);
setUser({
username: new_user.name,
email: new_user.email,
image: new_user.image_link
});
}
const showUser = () => {
console.log(user);
}
const logout = () => {
setUser({});
}
return (
<UserContext.Provider value={{ user, storeUser, showUser }}>
{props.children}
</UserContext.Provider>
)
}
export default UserContextProvider
[provider] .tsx
import React, { useContext } from "react";
import { Container, CircularProgress, Typography } from "@material-ui/core";
import { makeStyles, Theme } from "@material-ui/core/styles";
import { } from "@material-ui/icons";
import Router from 'next/router'
import UserContextProvider, { UserContext } from '../../components/UserContextProvider';
const styles = makeStyles((theme: Theme) => ({
root: {
width: "100vw",
height: "100vh",
display: "flex",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
},
title: {
marginTop: theme.spacing(2),
},
error: {
textAlign: "center",
},
}));
interface Props {
provider: string;
code: string;
classes: any;
}
function LoginPage(props: Props) {
const [error, setError] = React.useState(false);
const { storeUser, showUser } = useContext(UserContext);
const googleLogin = () => {
fetch("/api/login/google", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
code: props.code,
}),
})
.then((resp) => resp.json())
.then((res) => {
fetch(`${process.env.NEXT_PUBLIC_BACKEND_URL}/account/social_login`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
mode: "cors",
body: JSON.stringify({
id_token: res.id_token,
provider: "google",
}),
})
.then((resp) => resp.json())
.then((response) => {
localStorage.token = response.token;
document.cookie = `token=${response.token}; path=/; max-age=${
60 * 60 * 24 * 100
}`;
storeUser({
name: response.user.name,
email: response.user.email,
image_link: response.user.image_link
});
//This shows an empty object
showUser();
Router.push("/")
})
.catch((e) => {
console.log(e);
setError(true)
});
})
.catch((err) => {
console.log(err);
setError(true)
})
}
//This works
React.useEffect(() => {
storeUser({
name: "wqygubcjqnc",
email: "asbcascacsj",
image_link: "asjbcjasnck"
});
showUser();
});
const facebookLogin = () => {
fetch("/api/login/facebook", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
code: props.code,
}),
})
.then((resp) => resp.json())
.then((res) => {
fetch(`${process.env.NEXT_PUBLIC_BACKEND_URL}/login`, {
method: "POST",
body: JSON.stringify({
access_token: res.access_token,
provider: "facebook",
}),
})
.then((resp) => resp.json())
.then((response) => {
localStorage.token = response.token;
window.location.href = "/";
})
.catch((e) => {
console.log(e);
setError(true)
});
})
.catch((err) => {
console.log(err);
setError(true)
});
}
React.useEffect(() => {
if (props.provider == "google") googleLogin();
else if (props.provider == "facebook") facebookLogin();
else alert("Invalid login provider");
}, [])
const classes = styles()
return (
<UserContextProvider>
<Container className={classes.root}>
{error ? (
<React.Fragment>
<Typography className={classes.error} variant="h6" color="error">
Something went wrong. Please try again. If the problem still
exists, contact the administrator.
</Typography>
</React.Fragment>
) : (
<React.Fragment>
<CircularProgress size={"4rem"} />
<Typography variant="h6" className={classes.title}>
Logging you in
</Typography>
</React.Fragment>
)}
</Container>
</UserContextProvider>
);
}
export const getServerSideProps = async (context: any) => {
return {
props: {
provider: context.params?.provider,
code: context.query.code,
},
};
};
export default LoginPage
我目前仅使用Google登录名,因此请忽略Facebook登录功能。
答案 0 :(得分:0)
实际上,上下文值未显示最新值,因为在设置上下文后立即记录上下文,该值不会更新, 每当您更新React Context时,所有使用该上下文的组件都将使用更新的context值重新呈现,因此我们可以做的是将逻辑分离到单独的处理程序中,当使用用户响应更新上下文时,这些处理程序将被调用useEffect
/* in Login page component*/
const { user, storeUser, showUser } = useContext(UserContext);
const handleLogin = () => {
//any logic for handling login
showUser();
Router.push("/")
}
useEffect(() => {
// will get called when the user response is updated
handleLogin()
}, [user]);
// in similar way for error
useEffect(() => {
setError(true)
}, [error]);
/*in function googleLogin just update the context value ,
and the handling of the login functionality will be handled by the useEffect and
handleLogin function */
const googleLogin = () => {
//rest of the code
storeUser({
name: response.user.name,
email: response.user.email,
image_link: response.user.image_link
});
}