我们有 Node * removeDuplicates( Node *head)
{
map <int, int> duplicates;
Node* temp=head;
while(temp){
duplicates[temp->data]=1;
temp=temp->next;
}
Node* curr=head;
Node* prev=NULL;
while(curr){
if(duplicates[curr->data]==1){
duplicates[curr->data]=0;
prev=curr;
}
else{
prev->next=curr->next;
delete(curr);
}
curr=prev->next;
}
return head;
}
用于设置我们可以在整个应用程序中使用的用户对象。我们的 UserContext
每次都继续执行,并且即使依赖项没有改变也不必要地进行 api 调用。
UserContext
每当我们导航到 React 应用程序中的不同页面时,我们都会看到“用户”路由每次都被调用,即使令牌没有更新。我们的令牌仅在用户注销时更改。
我们的 AppRouter 如下所示;
import React, { useState, useEffect } from 'react'
import APIService from './utils/APIService';
import { getCookies } from './utils/Helper';
const UserContext = React.createContext();
const UserContextProvider = (props) => {
const [token, setToken] = useState(getCookies('UserToken'));
const [user, setUser] = useState(null);
useEffect(() => {
console.log('Inside userContext calling as token ', token)
fetchUserInfo();
}, [token]);
const fetchUserInfo = async() => {
if (token) {
let userRes = await APIService.get(`/user?token=${token}`);
console.log('User route called')
setUser(userRes.data);
}
}
/*
If user logoff or login, update token from child component
*/
const refreshToken = (newToken) => {
//token = newToken;
setToken(newToken);
fetchUserInfo()
}
return (
<UserContext.Provider value={{user, token, refreshToken}}>
{props.children}
</UserContext.Provider>
);
}
export { UserContextProvider, UserContext }
这是我们的内部应用,因此我们希望用户可以登录 30 天,而不必每次都保持登录状态。因此,当用户第一次登录时,我们为他们创建一个令牌并将该令牌保存在 cookie 中。因此,如果用户关闭浏览器并再次返回,我们会在 cookie 中检查令牌。如果令牌存在,我们会调用 API 来获取用户信息并在我们的上下文中设置用户。这是不工作的部分,它在导航到应用程序中的每条路线的过程中不断调用我们的用户 api。
这是我们的 login.js
import React from 'react';
import AppRouter from "./AppRouter";
import { Container } from 'react-bootstrap';
import Header from './components/Header';
import { ToastProvider, DefaultToastContainer } from 'react-toast-notifications';
import 'bootstrap/dist/css/bootstrap.css';
import './scss/styles.scss';
import { UserContextProvider } from './UserContextProvider';
export default function App() {
const ToastContainer = (props) => (
<DefaultToastContainer
className="toast-container"
style={{ zIndex:100,top:50 }}
{...props}
/>
);
return (
<UserContextProvider>
<ToastProvider autoDismiss={true} autoDismissTimeout={3000} components={{ ToastContainer }}>
<Container fluid>
<Header />
<AppRouter />
</Container>
</ToastProvider>
</UserContextProvider>
)
}
我们的 userContext 如下所示
import React, { useState, useContext } from 'react';
import { setCookies } from '../../utils/Helper';
import APIService from '../../utils/RestApiService';
import { UserContext } from '../../UserContextProvider';
import queryString from 'query-string';
import './_login.scss';
const Login = (props) => {
const [email, setEmail] = useState(null);
const [password, setPassword] = useState(null);
const [error, setError] = useState(null);
const { siteId } = props;
const { refreshToken} = useContext(UserContext);
const onKeyPress = (e) => {
if (e.which === 13) {
attemptLogin()
}
}
let params = queryString.parse(props.location.search)
let redirectTo = "/"
if (params && params.redirect)
redirectTo = params.redirect
const attemptLogin = async () => {
const payload = {
email: email,
password: password,
siteid: siteId
};
let response = await APIService.post('/login', payload);
console.log('response - ', response)
if (response.status === 200) {
const { data } = response;
setCookies('UserToken', data.token);
refreshToken(data.token)
window.location.replace(redirectTo);
}
else {
const { error } = response.data;
setError(error);
}
}
const renderErrors = () => {
return (
<div className="text-center login-error">
{error}
</div>
)
}
return (
<div className="login-parent">
<div className="container">
<div className="login-row row justify-content-center align-items-center">
<div className="login-column">
<div className="login-box">
<form className="login-form form">
<h3 className="login-form-header text-center">Login</h3>
<div className="form-group">
<label>Email:</label>
<br/>
<input
onChange={e => setEmail(e.target.value)}
placeholder="enter email address"
type="text"
onKeyPress={onKeyPress}
className="form-control"/>
</div>
<div className="form-group">
<label>Password:</label>
<br/>
<input
onChange={e => setPassword(e.target.value)}
placeholder="enter password"
type="password"
className="form-control"/>
</div>
<div className="form-group">
<button
className="btn btn-secondary btn-block"
onClick={attemptLogin}
type="button">
Login
</button>
</div>
{error ? renderErrors() : null}
</form>
</div>
</div>
</div>
</div>
</div>
)
}
export default Login;
我们的 getCookies 函数使用 Universal-cookies 包简单地读取 cookie
import React, { useState, useEffect } from 'react'
import APIService from './utils/APIService';
import { getCookies } from './utils/Helper';
const UserContext = React.createContext();
const UserContextProvider = (props) => {
const [token, setToken] = useState(getCookies('UserToken'));
const [user, setUser] = useState(null);
useEffect(() => {
if (!token) return;
console.log('Inside userContext calling as token ', token)
fetchUserInfo();
}, [token]);
const fetchUserInfo = async() => {
if (token) {
let userRes = await APIService.get(`/user?token=${token}`);
console.log('User route called')
setUser(userRes.data);
}
}
/*
If user logoff or login, update token from child component
*/
const refreshToken = (newToken) => {
//token = newToken;
setToken(newToken);
fetchUserInfo()
}
return (
<UserContext.Provider value={{user, token, refreshToken}}>
{props.children}
</UserContext.Provider>
);
}
export { UserContextProvider, UserContext }
答案 0 :(得分:6)
所以我尝试使用 CodeSandbox 复制您的问题,这些是我根据您的代码发现的结果:
您的上下文有一个 useEffect
,它依赖于 token
。当您调用 refreshToken
时,您会更新 token
,它会自动触发 useEffect
并调用 fetchUserInfo
。因此,您无需在 fetchUserInfo
中的 setToken
之后调用 refreshToken
。您的上下文如下所示:
const UserContext = React.createContext();
const UserContextProvider = (props) => {
const [token, setToken] = useState(getCookies("UserToken"));
const [user, setUser] = useState(null);
useEffect(() => {
console.log("Inside userContext calling as token ", token);
fetchUserInfo();
}, [token]);
const fetchUserInfo = async () => {
if (token) {
let userRes = await APIService.get(`/user?token=${token}`);
console.log('User route called')
setUser(userRes.data);
}
};
const refreshToken = (newToken) => {
setToken(newToken);
};
return (
<UserContext.Provider value={{ user, token, refreshToken }}>
{props.children}
</UserContext.Provider>
);
};
export { UserContextProvider, UserContext };
现在进入您的路由,因为您没有包含 AppRouter
的代码 我不得不假设您将 react-router
与 Switch
组件一起使用. (如 CodeSandbox 中所示)。
我看到您的 Login
组件中有一行是 window.location.replace(redirectTo);
。当您这样做时,整个页面会刷新(重新加载?)并且 React 会触发重新渲染,这就是我认为您的上下文方法再次触发的原因。
而是使用 history
中的 react-router
API (再次,我的假设) 像这样,
let history = useHistory();
history.push(redirectTo);
如果你想玩,这里是沙盒: