React 路由器 <Redirect> 未在状态下重定向

问题描述 投票:0回答:2

/dashboard
不是
user
时,应用程序应重定向到
null
。用户在第一次渲染中是
null
,但
useEffect()
应该从本地存储中获取并存储用户数据。然后,三元运算符应该触发
<Redirect to='/dashboard' />
并重定向到仪表板页面。但是,它并没有这样做。每当我刷新时,即使 localStorage 中有数据,它也会一直在
/login
显示登录页面。

我做错了什么或者如何解决这个问题?

const App = () => {
    const [user, setUser] = useState(null)

    useEffect(() => {
        const loggedUserJSON = window.localStorage.getItem('loggedUser')

        if (loggedUserJSON) {
            const user = JSON.parse(loggedUserJSON)
            setUser(user)
            noteService.setToken(user.token)
        }
    }, [])

    return (
        <Router>
            <Switch>
                <Route exact path='/'>
                    {user
                        ? <Redirect to='/dashboard' />
                        : <Redirect to='/login' />
                    }
                </Route>
                <Route exact path='/login'>
                    <LogIn />
                </Route>
                <Route exact path='/dashboard'>
                    <Dashboard />
                </Route>
            </Switch>
        </Router>
    )

reactjs react-router local-storage react-router-dom react-state
2个回答
1
投票

问题

问题是,在初始渲染时,

user
状态为
null
,并且会重定向到“/login”。当您重新加载页面时,如果路径仍然是“/login”,则无论 user 状态如何,它都不会完全
匹配“/”,并且不会发生重定向。

解决方案

从 localStorage 初始化状态,而不是等待渲染周期。这至少允许您在第一次渲染而不是在第二次(或更高版本)重新渲染时检查

user
状态。对
Switch
组件中的路由进行重新排序,以从 more 特定到 less 特定进行指定。重定向应该放在最后,以便其他路径有机会首先匹配和渲染。

const initializeState = () => JSON.parse(window.localStorage.getItem('loggedUser'));

const App = () => {
  const [user] = useState(initializeState());

  useEffect(() => {
    noteService.setToken(user.token);
  }, [user]);

  return (
    <Router>
      <Switch>
        <Route path='/login'>
          <LogIn />
        </Route>
        <Route path='/dashboard'>
          <Dashboard />
        </Route>
        <Redirect to={user ? '/dashboard' : '/login'} />
      </Switch>
    </Router>
  );
};

这并不能完全解决用户已经在子路由上的页面重新加载问题。为此,您应该实现一个

ProtectedRoute
组件并将
user
状态作为道具传递。如果存在
user
对象,它会渲染常规
Route
组件并传递道具,否则它会渲染
Redirect
并将用户弹回登录路由。

const ProtectedRoute = ({ user, ...props }) => user ? (
  <Route {...props} />
) : (
  <Redirect to="/login" />
);

const initializeState = () => JSON.parse(window.localStorage.getItem('loggedUser'));

const App = () => {
  const [user] = useState(initializeState());

  useEffect(() => {
    noteService.setToken(user.token);
  }, [user]);

  return (
    <Router>
      <Switch>
        <Route path='/login'>
          <LogIn />
        </Route>
        <ProtectedRoute path='/dashboard' user={user} >
          <Dashboard />
        </ProtectedRoute>
        <Redirect to={user ? '/dashboard' : '/login'} />
      </Switch>
    </Router>
  );
};

0
投票

如果您使用的是版本 6,请阅读以下内容:reactrouter.com/docs/en/v6/upgrading/v5

特别是它告诉您删除直接位于

<Redirect>
内的任何
<Switch>
元素的部分。

© www.soinside.com 2019 - 2024. All rights reserved.