Javascript 如何在React的父组件中检测localstorage集
我有一个身份验证服务,在成功登录后设置localstorage令牌 认证服务:Javascript 如何在React的父组件中检测localstorage集,javascript,reactjs,react-router,react-router-dom,react-router-v4,Javascript,Reactjs,React Router,React Router Dom,React Router V4,我有一个身份验证服务,在成功登录后设置localstorage令牌 认证服务: async function login(email, password, remember) { const data = await ApiClient.post(`/api/auth`, { email: email, password: password, remember: remember }); localStorage.setItem('token', data.token);
async function login(email, password, remember) {
const data = await ApiClient.post(`/api/auth`, {
email: email, password: password, remember: remember
});
localStorage.setItem('token', data.token);
return data.token;
}
async function logout() {
localStorage.removeItem('token');
}
export const authenticationService = {
login,
logout,
get currentUserValue () { return localStorage.getItem('token') }
}
App.js
{ authenticationService.currentUserValue &&
<Menu>Logged In</Menu> }
<Switch>
<PrivateRoute path="/dashboard" component={Dashboard} />
<Route path="/login" component={Login} />
<Route component={Error404} />
</Switch>
async function login(e) {
e.preventDefault();
try {
const token = await authenticationService.login(email, password, remember);
setErrorMsg('');
history.push('/dashboard');
} catch (err) {
if(err.response.status === 401) {
setErrorMsg('Unauthorized access, please login again.');
}
}
}
<form className={classes.form} noValidate onSubmit={login}>
<TextField value={email} />
<TextField value={password} />
<FormControlLabel
control={<Checkbox value="remember" color="primary" />}
label="Remember me"
onChange={(e) => setRemember(e.target.value)}
value={remember}
/>
<Button type="submit">Sign In</Button>
</form>
{authenticationService.currentUserValue&&
登录}
Login.js
{ authenticationService.currentUserValue &&
<Menu>Logged In</Menu> }
<Switch>
<PrivateRoute path="/dashboard" component={Dashboard} />
<Route path="/login" component={Login} />
<Route component={Error404} />
</Switch>
async function login(e) {
e.preventDefault();
try {
const token = await authenticationService.login(email, password, remember);
setErrorMsg('');
history.push('/dashboard');
} catch (err) {
if(err.response.status === 401) {
setErrorMsg('Unauthorized access, please login again.');
}
}
}
<form className={classes.form} noValidate onSubmit={login}>
<TextField value={email} />
<TextField value={password} />
<FormControlLabel
control={<Checkbox value="remember" color="primary" />}
label="Remember me"
onChange={(e) => setRemember(e.target.value)}
value={remember}
/>
<Button type="submit">Sign In</Button>
</form>
异步函数登录(e){
e、 预防默认值();
试一试{
const token=wait authenticationService.login(电子邮件、密码、记住);
setErrorMsg(“”);
history.push('/dashboard');
}捕捉(错误){
如果(err.response.status==401){
setErrorMsg('未经授权的访问,请重新登录');
}
}
}
setmemory(e.target.value)}
值={记住}
/>
登录
当我在
login.js
中使用表单登录时,它不会呈现App.js
中的Logged
菜单。当我们在localstorageget currentUserValue(){return localstorage.getItem('token')}
和登录后的render菜单中设置令牌值时,是否有重新呈现的方法?您需要将令牌存储在某个状态的某个位置。然后根据标记的状态呈现视图
// Login.js
const LoginComponent = () => {
const { login, logout } = useAuthenticationService();
async function handleSubmit(e) {
e.preventDefault();
try {
await login(email, password, remember);
history.push('/dashboard');
} catch (err) {
if(err.response.status === 401) {
setErrorMsg('Unauthorized access, please login again.');
}
}
}
render(
<form className={classes.form} noValidate onSubmit={handleSubmit}>
<TextField value={email} />
<TextField value={password} />
<FormControlLabel
control={<Checkbox value="remember" color="primary" />}
label="Remember me"
onChange={(e) => setRemember(e.target.value)}
value={remember}
/>
<Button type="submit">Sign In</Button>
</form>
);
}
创建钩子并分离一些关注点。身份验证现在需要获取和存储令牌。在这些钩子中拆分这两个钩子:存储钩子和身份验证钩子
存储挂钩将创建一个状态,在该状态下您可以读取和写入令牌。它还根据令牌中的值更新localStorage
项
// Login.js
const LoginComponent = () => {
const { login, logout } = useAuthenticationService();
async function handleSubmit(e) {
e.preventDefault();
try {
await login(email, password, remember);
history.push('/dashboard');
} catch (err) {
if(err.response.status === 401) {
setErrorMsg('Unauthorized access, please login again.');
}
}
}
render(
<form className={classes.form} noValidate onSubmit={handleSubmit}>
<TextField value={email} />
<TextField value={password} />
<FormControlLabel
control={<Checkbox value="remember" color="primary" />}
label="Remember me"
onChange={(e) => setRemember(e.target.value)}
value={remember}
/>
<Button type="submit">Sign In</Button>
</form>
);
}
返回token
和setToken
函数,供其他组件或挂钩使用
const useTokenStorage = () => {
const [ token, setToken ] = useState(() => {
const token = localStorage.getItem('token');
return token !== null ? token : ''
});
useEffect(() => {
if (token === '') {
localStorage.removeItem('token');
} else {
localStorage.setItem('token', token);
}
}, [token]);
return [ token, setToken ];
};
身份验证服务钩子将使用存储钩子来设置令牌的值。login
和logout
功能将使用setToken
更新token
的值,这反过来将更新localStorage
从钩子中返回令牌
,登录
和注销
功能,因此令牌
只能通过登录
和注销
功能更新。当然,还可以通过标记
属性读取
const useAuthenticationService = () => {
const [ token, setToken ] = useTokenStorage();
const login = async (email, password, remember) => {
const data = await ApiClient.post(`/api/auth`, {
email: email, password: password, remember: remember
});
setToken(data.token);
};
const logout = () => {
setToken('');
};
return { token, login, logout };
};
使用组件中的useAuthenticationService
钩子,在该组件中,您需要根据token
确定要呈现的内容,就像在您的App.js中一样
// App.js
const AppComponent = () => {
const { token } = useAuthenticationService();
return (
{ token && <Menu>Logged In</Menu> }
<Switch>
<PrivateRoute path="/dashboard" component={Dashboard} />
<Route path="/login" component={Login} />
<Route component={Error404} />
</Switch>
);
};
token
现在应该与localStorage
同步,即使在您导航或刷新页面时也是如此。我建议您在存储/状态中的某个位置反映该值,您可以使用useffect
挂钩或使用。在React中很难跟踪React组件外部存储的数据,因为没有监视它是否会触发重新呈现的更改。我只是尝试了一下,它似乎在登录和history,push('/dashboard')
之后仍然不会呈现更改令牌。它仅在我刷新仪表板页面上的整个页面时显示。我认为挑战在于App.js
是Login.js
的父函数,并且在Login.js
中调用该函数时不会触发App.js
上父函数上组件的重新呈现。我通过将登录函数从App.js
(父级)传递到login.js
(子级)来实现这一点,因此子级实际上调用了从父级实例化的登录函数,该函数触发了App.js
的重新呈现,因为父级的状态发生了变化!干得好。您是否也考虑过使用上下文API?上下文API是否比从父级传递函数更好?Meh,前提是您可能在更深的嵌套子级中使用令牌,或者仅在无法将其作为道具传递的地方使用令牌。这不是更好,只是更灵活一点。