反应路由器dom重定向问题。更改网址,不呈现组件

时间:2019-07-21 11:33:20

标签: reactjs react-redux react-router react-router-dom

问题::当我使用history.push()时,可以看到浏览器更改了url,但是它没有使我的组件在路径上侦听。仅在刷新页面时才会呈现。

App.js文件:

import React from "react";
import { BrowserRouter as Router, Route } from "react-router-dom";
import { Provider } from "react-redux";
import PropTypes from "prop-types";

//Components
import LoginForm from "../LoginForm/LoginForm";
import PrivateRoute from "../PrivateRoute/PrivateRoute";
import ServerList from "../ServerList/ServerList";

const App = ({ store }) => {
  const isLoggedIn = localStorage.getItem("userToken");

  return (
    <Router>
      <Provider store={store}>
        <div className="App">
          {isLoggedIn !== true && (
            <Route exact path="/login" component={LoginForm} />
          )}
          <PrivateRoute
            isLoggedIn={!!isLoggedIn}
            path="/"
            component={ServerList}
          />
        </div>
      </Provider>
    </Router>
  );
};

App.propTypes = {
  store: PropTypes.object.isRequired
};

export default App;

我在LoginForm内向API发出请求,并在完成程序后使用.then()重定向我的用户:

.then(() => {
  props.history.push("/");
})

会发生什么:浏览器将网址从/login更改为/,但是除非渲染页面重新加载,否则不会呈现在/路由上侦听的组件。

在我的/组件中,我使用useEffect()钩子向API发出另一个请求,该请求将提取数据并将其打印在return()内。如果我在console.loguseEffect()发生两次,则假定是第一个,当我使用useState()钩子将API中的数据存储在组件状态内时。

编辑:根据要求添加PrivateRoute组件:

import React from "react";
import { Route, Redirect } from "react-router-dom";

const PrivateRoute = ({ component: Component, isLoggedIn, ...rest }) => {
  return (
    <Route
      {...rest}
      render={props =>
        isLoggedIn === true ? (
          <Component {...props} />
        ) : (
          <Redirect to={{ pathname: "/login" }} />
        )
      }
    />
  );
};

export default PrivateRoute;

我已经尝试过的方法: 1)用default export包装我的withRouter()

export default withRouter(connect(mapStateToProps, mapDispatchToProps)(LoginForm));

2)创建自定义history并将其作为prop传递给Router

react-router-dom的版本为^5.0.1react-router相同,5.0.1

1 个答案:

答案 0 :(得分:0)

您的代码有两个错误。

  1. 您没有使用<switch>组件来包装路由。因此,每个路由都会处理所有路由,并且每个<route>的所有组件都会被渲染。

  2. 您正在使用本地存储在组件之间交换信息。但是,本地存储中的更改无法做出反应,因此不会触发组件重新渲染。要解决此问题,您应该在App组件中使用局部状态(通过将其转换为类或使用钩子)。

所以纠正后的代码看起来像

const App = ({ store }) => {
  const [userToken, setUserToken] = useState(localStorage.getItem("userToken")); // You can read user token from local store. So on after token is received, user is not asked for login

  return (
    <Router>
      <Provider store={store}>
        <div className="App">
          <Switch>
            {!!userToken !== true && (
              <Route exact path="/login"
                render={props => <LoginForm {...props} setUserToken={setUserToken} />}
              />
            )}
            <PrivateRoute
              isLoggedIn={!!userToken}
              path="/"
              component={ServerList}
            />
          </Switch>
        </div>
      </Provider>
    </Router>
  );
};

并且LoginForm应该使用setUserToken来更改App组件中的用户令牌。它还可以将用户令牌存储在本地存储中,以便不要求页面刷新用户登录,而是使用存储的令牌。

此外,请确保不要在<Switch></Switch>之间放置任何内容。否则路由将无法工作。

这里是working sample