以编程方式使用react-router进行导航

时间:2017-05-23 06:54:19

标签: javascript reactjs redux

我正在开发一个应用程序,我在其中检查用户是否loggedIn我必须显示登录表单,否则dispatchaction将改变路由并加载其他零件。这是我的代码:

    render() {
         if (isLoggedIn) {
             // dispatch an action to change the route
         }
         // return login component
         <Login />
    }

我怎样才能实现这一点,因为我无法改变渲染功能中的状态。

8 个答案:

答案 0 :(得分:34)

考虑到您使用的是react-router v4

将您的组件与withRouter一起使用,并使用道具中的history.push来更改路线。只有在组件没有收到withRouter道具时才需要使用Router,这可能发生在组件是路由器呈现的组件的嵌套子级而您没有将Router支持传递给它,或者当组件根本没有链接到路由器时,它被呈现为路由中的单独组件。

import {withRouter} from 'react-router';

class App extends React.Component {
     ...
     componenDidMount() {
        // get isLoggedIn from localStorage or API call
        if (isLoggedIn) {
             // dispatch an action to change the route
             this.props.history.push('/home');
        }
     }
     render() {
         // return login component
         return <Login />
    }
}


export default withRouter(App);
  

重要提示

     

如果您使用withRouter来阻止更新被阻止   shouldComponentUpdate,重要的是withRouter包装。{1}}   实现shouldComponentUpdate的组件。例如,何时   使用Redux:

     

//这可以解决shouldComponentUpdate

withRouter(connect(...)(MyComponent))
     

//这不是

connect(...)(withRouter(MyComponent))

或者您可以使用重定向

import {withRouter} from 'react-router';

class App extends React.Component {
     ...
     render() {
         if(isLoggedIn) {
              return <Redirect to="/home"/>
         }
         // return login component
         return <Login />
    }
}

使用react-router v2 or react-router v3,您可以使用context动态更改路径,如

class App extends React.Component {
     ...
     render() {
         if (isLoggedIn) {
             // dispatch an action to change the route
             this.context.router.push('/home');
         }
         // return login component
         return <Login />
    }
}

App.contextTypes = {
    router: React.PropTypes.object.isRequired
}
export default App;

或使用

import { browserHistory } from 'react-router';
browserHistory.push('/some/path');

答案 1 :(得分:3)

在react-router版本4中:

import React from 'react'
import { BrowserRouter as Router, Route, Redirect} from 'react-router-dom'

const Example = () => (

  if (isLoggedIn) {
    <OtherComponent />

  } else {

    <Router>
      <Redirect push to="/login" />
      <Route path="/login" component={Login}/>
    </Router>

  }
)

const Login = () => (
    <h1>Form Components</h1>
    ...
)

export default Example;

答案 2 :(得分:2)

另一种方法是使用Thunk式异步操作(安全/允许有副作用)来处理这个问题。

如果您使用Thunk,则可以使用history<Router>组件和Thunk操作注入相同的thunk.withExtraArgument对象,如下所示:

import React from 'react'
import { BrowserRouter as Router, Route, Redirect} from 'react-router-dom'
import { createBrowserHistory } from "history"
import { applyMiddleware, createStore } from "redux"
import thunk from "redux-thunk"

const history = createBrowserHistory()

const middlewares = applyMiddleware(thunk.withExtraArgument({history}))
const store = createStore(appReducer, middlewares)

render(
  <Provider store={store}
    <Router history={history}>
      <Route path="*" component={CatchAll} />
    </Router
  </Provider>,
appDiv)

然后在您的动作创建者中,您将拥有一个可以安全地与ReactRouter一起使用的history实例,因此如果您未登录,则可以触发常规的Redux事件:

// meanwhile... in action-creators.js
export const notLoggedIn = () => {
  return (dispatch, getState, {history}) => {
    history.push(`/login`)
  }
}

这样做的另一个好处是,现在,url更容易处理,因此我们可以在查询字符串上添加重定向信息等。

您可以尝试在Render方法中执行此检查,但如果它导致问题,您可以考虑在componentDidMount或生命周期的其他位置执行此操作(尽管我也理解坚持使用无状态功能的愿望Compeonents!)

您仍然可以使用Redux和mapDispatchToProps将动作创建器注入到您的组件中,因此您的组件仍然只是松散地连接到Redux。

答案 3 :(得分:0)

render(){ 

    return (
        <div>  
            { this.props.redirect ? <Redirect to="/" /> :'' } 
            <div>
                add here component codes
            </div>
        </div>
    );
} 

答案 4 :(得分:0)

react-router v4 上实施此操作时遇到的问题。这是一个用于以编程方式浏览React应用的可行解决方案。

history.js

import createHistory from 'history/createBrowserHistory'

export default createHistory()

App.js或Route.jsx。将历史记录作为道具传递给路由器。

import { Router, Route } from 'react-router-dom'
import history from './history'
...
<Router history={history}>
 <Route path="/test" component={Test}/>
</Router>

您可以使用push()进行导航。

import history from './history' 

...

render() {
     if (isLoggedIn) {
         history.push('/test') // this should change the url and re-render Test component
     }
     // return login component
     <Login />
}

全部感谢此评论:https://github.com/ReactTraining/react-router/issues/3498#issuecomment-301057248

答案 5 :(得分:0)

我建议您使用 connected-react-router (连接反应路由器) https://github.com/supasate/connected-react-router 如果需要的话,甚至可以从化简器/动作中进行导航。 它有据可查且易于配置

答案 6 :(得分:0)

这是我的手柄loggedInreact-router v4

如果用户已登录,则允许PrivateRoute输入path并将令牌保存到localStorge

    function PrivateRoute({ component: Component, ...rest }) {
     return (
        <Route
          {...rest}
          render={props => (localStorage.token) ? <Component {...props} /> : (
            <Redirect
              to={{
                pathname: '/signin',
                state: { from: props.location },
              }}
            />
          )
          }
        />
      );
    }

在此处定义应用中的所有路径

export default (
  <main>
    <Switch>
      <Route exact path="/signin" component={SignIn} />
      <Route exact path="/signup" component={SignUp} />
      <PrivateRoute path="/" component={Home} />
    </Switch>
  </main>
);

答案 7 :(得分:0)

我能够在无状态功能组件中使用history,方法是使用withRouter(需要忽略打字稿警告):

import { withRouter } from 'react-router-dom';

...

type Props = { myProp: boolean };

// @ts-ignore
export const MyComponent: FC<Props> = withRouter(({ myProp, history }) => {

...

})