react-router私有路由/重定向不起作用

IT技术 reactjs redux react-router react-redux
2021-03-30 16:42:41

我已经稍微调整了私有路由的 React Router 示例,以便与 Redux 配合使用,但在链接或重定向到其他“页面”时不会呈现任何组件。该示例可以在这里找到:

https://reacttraining.com/react-router/web/example/auth-workflow

他们的 PrivateRoute 组件如下所示:

const PrivateRoute = ({ component: Component, ...rest }) => (
  <Route {...rest} render={props => (
    fakeAuth.isAuthenticated ? (
      <Component {...props}/>
    ) : (
      <Redirect to={{
        pathname: '/login',
        state: { from: props.location }
      }}/>
    )
  )}/>
)

但是,因为我已经将它合并到一个 Redux 应用程序中,所以我不得不稍微调整 PrivateRoute 以便我可以访问 redux 商店,以及路由props:

const PrivateRouteComponent = (props) => (
    <Route {...props.routeProps} render={() => (
    props.logged_in ? (
        <div>{props.children}</div>
        ) : (
        <Redirect to={{
            pathname: '/login',
            state: { from: props.location }
        }} /> )
    )} />
);

const mapStateToProps = (state, ownProps) => {
    return {
        logged_in: state.auth.logged_in,
        location: ownProps.path,
        routeProps: {
            exact: ownProps.exact,
            path: ownProps.path
        }
    };
};

const PrivateRoute = connect(mapStateToProps, null)(PrivateRouteComponent);
export default PrivateRoute

每当我未登录并点击 PrivateRoute 时,我都会正确重定向到 /login。但是,例如在登录并使用<Redirect .../>,或单击<Link ...>PrivateRoute 中的任何内容后,URI 会更新,但视图不会。它停留在同一个组件上。

我究竟做错了什么?


只是为了完成图片,在应用程序中index.js有一些不相关的东西,并且路由是这样设置的:

ReactDOM.render(
    <Provider store={store}>
        <App>
            <Router>
                <div>
                    <PrivateRoute exact path="/"><Home /></PrivateRoute>
                    // ... other private routes
                    <Route path="/login" component={Login} />
                </div>
            </Router>
        </App>
    </Provider>,
    document.getElementById('root')
);
6个回答

你需要Route<Switch>标签包裹你的

ReactDOM.render(
<Provider store={store}>
    <App>
        <Router>
            <div>
                <Switch>
                   <PrivateRoute exact path="/"><Home /></PrivateRoute>
                   // ... other private routes
                   <Route path="/login" component={Login} />
                </Switch>
            </div>
        </Router>
    </App>
</Provider>,
document.getElementById('root'));
我试图props.history.push在与 连接的组件内部使用withRouterPrivateRoute但没有Switch. 节省了我很多时间,谢谢!
2021-05-28 16:42:41
您必须让组件重新渲染。也可以将 PrivateRoute 设置为非纯路由:export default connect(mapStateToProps, null, null, { pure: false })(PrivateRoute);另请参阅此堆栈溢出
2021-06-12 16:42:41

设置私有路由不纯:

export default connect(mapStateToProps, null, null, {
  pure: false,
})(PrivateRoute);

这将让组件重新渲染。

请参阅:react-router-4-x-privateroute-not-working-after-connecting-to-redux

刚刚遇到同样的问题,我通过制作我的 App redux 容器并将 isAuthenticated 作为props传递给 PrivateRoute 来解决它

就是这样,希望能帮到你

const App = (props) => {
return (
  <Provider store={store}>
    <Router>
      <div>
        <PrivateRoute path="/secured" component={Secured} isAuthenticated={props.isAuthenticated} />
      </div>
    </Router>
  </Provider>
  );
};

const mapStateToProps = state => ({
  isAuthenticated: state.isAuthenticated
});

export default connect(mapStateToProps)(App);

然后在我的 PrivateRoute

const PrivateRoute = ({ component: Component, isAuthenticated, ...rest}) => (
<Route
  {...rest}
  render={props => (
    isAuthenticated
    ? (
       <Component {...props} />
    )
    : (<Redirect to={{ pathname: '/login', state: { from: props.location} }} />)
  )}
/>
);

export default PrivateRoute;
@Danijel,你摇滚!:-)
2021-05-24 16:42:41
谢谢,我稍后会研究这个!:-D
2021-06-05 16:42:41
我有类似的问题。事实上,我不想将 isAuthenticated 传递给 PrivateRoute 的每次使用,这就是我连接到 redux 的原因,但令人惊讶的是,直到任何其他 prop 传递给 <PrivateRoute 它才不起作用。我也把我的问题作为答案!!!以下
2021-06-15 16:42:41

我设法使用rest参数访问了以下数据mapStateToProps

const PrivateRoute = ({component: Component, ...rest}) => {
  const {isAuthenticated} = rest;

  return (
    <Route {...rest} render={props => (
      isAuthenticated ? (
        <Component {...props}/>
      ) : (
        <Redirect to={{
          pathname: '/login',
          state: {from: props.location}
        }}/>
      )
    )}
    />
  );
};

PrivateRoute.propTypes = {
  isAuthenticated: PropTypes.bool.isRequired,
};

function mapStateToProps(state) {
  return {
    isAuthenticated: state.user.isAuthenticated,
  };
}

export default connect(mapStateToProps)(PrivateRoute);
我必须这样做以及添加<Switch>到路线以使其工作。
2021-06-16 16:42:41

嗯,我觉得这个问题的答案真的应该更详细,所以我在这里,经过4个小时的挖掘。

当你用 connect() 包装你的组件时,React Redux 会在它上面实现 shouldComponentUpdate(如果你在 github 问题上搜索答案则是 sCU)并对 props 进行浅层比较(它遍历 props 对象中的每个键并检查值是否与 ' 相同===)。这在实践中意味着您的组件被视为Pure现在只有当它的props改变时它才会改变!这是这里的关键信息。第二个关键信息,React 路由器与上下文一起将位置、匹配和历史对象从路由器传递到路由组件。它不使用 props

现在让我们在实践中看看会发生什么,因为即使知道这一点,我发现它仍然非常棘手:

  • 案例

连接后,您的props有 3 个键:路径、组件和身份验证(由连接提供)。因此,实际上,您的包装组件根本不会在路由更改时重新渲染,因为它不在乎。当路线改变时,你的props不会改变,也不会更新。

  • 案例3

现在连接后你的props有 4 个键:path、component、auth 和 anyprop。这里的技巧是 anyprop 是每次调用组件时创建的对象。因此,每当您的组件被调用时,都会进行此比较:{a:1} === {a:1},这(您可以尝试)给您 false,因此您的组件现在每次都会更新。但是请注意,您的组件仍然不关心路线,它的孩子们关心。

  • 案例2

现在这就是这里的奥秘,因为我猜你在你的应用程序文件中调用了这一行,并且那里应该没有对“auth”的引用,并且你应该有一个错误(至少我是这样认为的)。我的猜测是您的 App 文件中的“auth”引用了在那里定义的对象。

现在我们该怎么办?

我在这里看到两个选项:

  1. 告诉 React Redux 您的组件不是纯组件,这将移除 sCU 注入,您的组件现在将正确更新。

    连接(mapStateToProps,空,空,{纯:假})(私人路由)

  2. 使用 WithRouter(),这将导致将位置、匹配和历史对象作为props注入到您的组件中。现在,我不知道内部结构,但我怀疑 React 路由器不会改变这些对象,因此每次路由更改时,它的 props 也会更改(sCU 返回 true)并且您的组件正确更新。这样做的副作用是你的 React 树现在被很多 WithRouter 和 Route 的东西污染了......

参考github问题:处理更新阻塞

您可以在此处看到 withRouter 旨在作为快速修复而不是推荐的解决方案。没有提到使用 pure:false 所以我不知道这个修复程序有多好。

我找到了第三个解决方案,尽管我不清楚它是否真的是比 withRouter 更好的解决方案,使用高阶组件。您将高阶组件连接到 Redux 存储,现在您的路由并不关心它渲染的内容,HOC 会处理它。

import Notlogged from "./Notlogged";    
function Isloggedhoc({ wrap: Component, islogged, ...props }) {
      return islogged ? <Component {...props} /> : <Notlogged {...props} />;
    }

const mapState = (state, ownprops) => ({
      islogged: state.logged,
      ...ownprops
    });

export default connect(mapState)(Isloggedhoc);

在你的 App.js 中

<Route path="/PrivateRoute" render={props => <Isloadedhoc wrap={Mycomponent} />} />

你甚至可以做一个咖喱函数来缩短它:

function isLogged(component) {
  return function(props) {
    return <Isloadedhoc wrap={component} {...props} />;
  };
}

像这样使用它:

<Route path="/PrivateRoute" render={isLogged(Mycomponent)} />
好吧,我认为这会在链接之后进行,但事实并非如此。我的答案旨在建立在他问题的具体细节之上,尽管它可以应用于原始问题。
2021-06-12 16:42:41