Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/403.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 如何在React的父组件中检测localstorage集_Javascript_Reactjs_React Router_React Router Dom_React Router V4 - Fatal编程技术网

Javascript 如何在React的父组件中检测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);

我有一个身份验证服务,在成功登录后设置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);
  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
菜单。当我们在localstorage
get 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,前提是您可能在更深的嵌套子级中使用令牌,或者仅在无法将其作为道具传递的地方使用令牌。这不是更好,只是更灵活一点。