React router v4 use declarative Redirect without rendering the current component

懵懂的女人 提交于 2020-01-02 08:07:48

问题


I am using a similar code like this to redirect in my app after users logged in. The code looks like the following:

import React, { Component } from 'react'
import { Redirect } from 'react-router'

export default class LoginForm extends Component {
  constructor () {
    super();
    this.state = {
      fireRedirect: false
    }
  }

  submitForm = (e) => {
    e.preventDefault()
    //if login success
    this.setState({ fireRedirect: true })
  }

  render () {
    const { from } = this.props.location.state || '/'
    const { fireRedirect } = this.state

    return (
      <div>
        <form onSubmit={this.submitForm}>
          <button type="submit">Submit</button>
        </form>
        {fireRedirect && (
          <Redirect to={from || '/home'}/>
        )}
      </div>
    )

  }
}

Works fine when a successful login has been triggered. But there is the case, that logged in users enter the login page and should be automatically redirected to the "home" page (or whatever other page).

How can I use the Redirect component without rendering the current component and without (as far as I understand discouraged) imperative pushing to the history (e.g. in componentWillMount)?


回答1:


Solution 1

You could use withRouter HOC to access history via props.

Import withRouter.

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

Then wrap with HOC.

// Example code
export default withRouter(connect(...))(Component)

Now you can access this.props.history. For example use it with componentDidMount().

componentDidMount() {
  const { history } = this.props;

  if (this.props.authenticated) {
    history.push('/private-route');
  }
}

Solution 2 Much better

Here is example on reacttraining.

Which would perfectly work for you.

But you just need to create LoginRoute to handle problem you described.

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

and inside <Router /> just replace

<Route path="/login" component={Login}/>

with

<LoginRoute path="/login" component={Login}/>

Now everytime somebody will try to access /login route as authenticated user, he will be redirected to /private-route. It's even better solution because it doesn't mount your LoginComponent if condition isn't met.




回答2:


Here is another solution which doesn't touch React stuff at all. E.g. if you need to navigate inside redux-saga.

Have file history.js:

import {createBrowserHistory} from 'history';
export default createBrowserHistory();

Somewhere where you define routes, don't use browser router but just general <Router/>:

import history from 'utils/history';

...

<Router history={history}>
  <Route path="/" component={App}/>
</Router>

That's it. Now you can use same history import and push new route.

In any part of your app:

import history from 'utils/history';
history.push('/foo');

In saga:

import {call} from 'redux-saga/effects';
import history from 'utils/history';

 ... 

history.push('/foo');
yield call(history.push, '/foo');


来源:https://stackoverflow.com/questions/44391262/react-router-v4-use-declarative-redirect-without-rendering-the-current-component

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!