2017-04-20 139 views
14

我已经稍微调整了专用路由的React路由器示例,以便与Redux一起玩,但在链接或重定向到其他“页面”时不显示任何组件。这个例子可以在这里找到:React路由器私有路由/重定向不起作用

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 } 
     }}/> 
    ) 
)}/> 
) 

但是,因为我已经在一个终极版的应用程序结合的话,我不得不调整PrivateRoute一点这样我就可以访问了Redux店,以及路线道具:

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,我是心病直接重定向到/登录。但是,例如,在登录并使用<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') 
); 

回答

4

只是有同样的问题,我解决它通过使我应用终极版容器和传球isAuthenticated为道具,以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; 
+0

谢谢,我会在晚些时候看看! :-D – Rein

+0

我有类似的问题。事实上,我不想通过isAuthenticated到每一次使用PrivateRoute,这是我连接到Redux的原因,但令人惊讶的是,直到任何额外的道具传递给

+0

@Danijel,你摇滚! :-) – kernix

0

我有类似的问题像@Rein。就我而言,PrivateRoute看起来与原始版本几乎相同,但只连接到Redux并在原始示例中使用它代替fakeAuth。

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

PrivateRoute.propTypes = { 
    auth: PropTypes.object.isRequired, 
    component: PropTypes.func.isRequired 
} 

const mapStateToProps = (state, ownProps) => { 
    return { 
    auth: state.auth 
    } 
}; 

export default connect(mapStateToProps)(PrivateRoute); 

使用和结果: -

  1. 不工作,但期待工作
    • <PrivateRoute path="/member" component={MemberPage} />
  2. 工作,但不希望用这样的
    • <PrivateRoute path="/member" component={MemberPage} auth={auth} />
  3. 工作。只是工作,但不希望被使用。从这一点可以理解,如果你将原始的PrivateRoute连接到Redux,你需要传递一些额外的道具(任何道具)来使PrivateRoute工作,否则它不起作用。 任何人,请对此行为给予一些提示。这是我主要关心的问题。As a New Question at
    • <PrivateRoute path="/member" component={MemberPage} anyprop={{a:1}} />
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')); 
+0

为什么这个有效? –

+0

您必须让组件重新呈现。它也可以将PrivateRoute设置为非纯粹的: 'export default connect(mapStateToProps,null,null,{pure:false})(PrivateRoute);' 请参阅本文[Stack Overflow](https:// stackoverflow。 com/questions/43892050/react-router-4-x-privateroute-not-working-after-connecting-to-redux) – worker11811

+0

我正在尝试在与'withRouter'连接的组件内部使用'props.history.push' ,没有'Switch',我的'PrivateRoute'不工作。为我节省了一堆时间,谢谢! – jordancooperman

2

我设法得到这个工作使用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); 
+0

我不得不这样做,以及添加''的路线,使其工作。 – worker11811

0

根据react-router documentation你可能只是换你connect功能与withRouter

// before 
export default connect(mapStateToProps)(Something) 

// after 
import { withRouter } from 'react-router-dom' 
export default withRouter(connect(mapStateToProps)(Something)) 

这个工作对我和我的观点开始被用在这种情况下的行车路线更新。

1

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

当你用connect()包装你的组件时,React Redux实现了shouldComponentUpdate(sCU,如果你在github问题上搜索答案)并且对道具进行浅层比较(它通过道具对象中的每个关键点并检查值与'==='相同)。在实践中意味着你的组件被认为是Pure只有当它的道具改变时,它才会改变!这里是关键信息。 第二个关键信息,React路由器与上下文一起工作,将路由器的位置,匹配和历史记录对象传递给Route组件。 它不使用道具

现在,让我们在实践中发生什么看,因为即使知道,我觉得还是相当棘手:

  • 案例:

连接后有3关键是你的道具:路径,组件和auth(由连接给出)。所以,事实上,你的封装组件不会在路由更改时重新渲染,因为它不关心。当路线改变时,你的道具不会改变,它不会更新。

  • 案例:

现在有4个按键到你的道具后连接:路径,组件,权威性和anyprop。这里的技巧是anyprop是每次调用组件时创建的对象。因此,无论何时调用组件,都会进行比较:{a:1} === {a:1},哪个(您可以尝试)会让您错误,所以您的组件现在每更新一次。但请注意,您的组件仍然不关心路由,它的孩子会这样做。

  • 案例:

现在,这奥秘在这里,因为我想你把这个线在你的应用程序文件,应该没有提及“权威性”,在那里,你应该有一个错误(至少这就是我所说的)。我的猜测是你的App文件中的“auth”引用了一个定义在那里的对象。

现在我们该怎么办?

在这里我看到两个选项:

  1. 泰尔阵营终极版,你的分量不是纯粹的,这将删除SCU注入和您的组件现在将正确更新。

    连接(mapStateToProps,NULL,NULL,{ 纯:假 })(PrivateRoute)

  2. 使用WithRouter(),这将导致当道具注入的位置,比赛和历史物件到您的组件。现在,我不知道内部结构,但是我怀疑React路由器不会改变这些对象,所以每当路由改变时,它的道具改变(sCU返回true)以及你的组件正确更新。这样做的副作用是,你的阵营树现在有很多的WithRouter和路线的东西污染......

参考GitHub的问题:Dealing with Update Blocking

你可以在这里看到,withRouter意作为quickfix,但不是推荐的解决方案。使用pure:false并没有提到,所以我不知道这个修复程序有多好。

我发现了第三个解决方案,虽然我不清楚它是否比使用高级组件的路由器更好的解决方案。你把你的高阶组件连接到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)} /> 
+0

嗯,我认为这会在[link](https://stackoverflow.com/a/43889596/8674856)之后出现,但它不会。我的答案旨在建立在他的问题的具体细节上,尽管它可以应用于原始问题。 – TheoH