it-roy-ru.com

Программная навигация с использованием реагирующего маршрутизатора

Я разрабатываю приложение, в котором я проверяю, не является ли пользователь loggedIn, я должен отобразить форму входа, иначе dispatch и action, которая изменила бы маршрут и загрузила другой компонент. Вот мой код:

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

Как я могу добиться этого, поскольку я не могу изменить состояния внутри функции рендеринга.

32
Gaurav Mehta

Учитывая, что вы используете react-router v4

Используйте ваш компонент с withRouter и используйте history.Push from props, чтобы изменить маршрут. Вам необходимо использовать withRouter только в том случае, если ваш компонент не получает реквизиты 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 оборачивал Компонент, который реализует shouldComponentUpdate. Например, когда используя Redux:

// Это обходит shouldComponentUpdate

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

// Это не 

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

или вы можете использовать Redirect

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');
29
Shubham Khatri

В реакции 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;
3
tgrrr

Другой альтернативой является обработка этого с использованием асинхронных действий в стиле 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)

Тогда в ваших создателях действий у вас будет экземпляр history, который можно безопасно использовать с ReactRouter, так что вы можете просто вызвать обычное событие Redux, если вы не вошли в систему:

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

Еще одним преимуществом этого является то, что теперь URL легче обрабатывать, поэтому мы можем поместить информацию о перенаправлении в строку запроса и т.д.

Вы можете попробовать выполнить эту проверку в ваших методах Render, но если это вызывает проблемы, вы можете рассмотреть возможность сделать это в componentDidMount или в другом месте жизненного цикла (хотя также я понимаю желание придерживаться функциональных компонентов без состояния!)

Вы по-прежнему можете использовать Redux и mapDispatchToProps для добавления создателя действий в ваш компонент, так что ваш компонент все еще слабо связан с Redux.

1
Chris Jaynes
render(){ 

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

Те, кто сталкивается с проблемами при реализации этого на Reaction-router v4. Вот рабочее решение для навигации по приложению реагирования программно.

history.js

import createHistory from 'history/createBrowserHistory'

export default createHistory()

App.js OR 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

0
reflexgravity

Я бы посоветовал вам использовать connected-реагирующий-маршрутизаторhttps://github.com/supasate/connected-react-router , Который помогает выполнять навигацию даже из редукторов/действий, если вы хотите . это хорошо документировано и легко настраивается

0
Denis Rudov