Programmatisch navigeren met react-router

Ik ontwikkel een applicatie waarin ik controleer of de gebruiker niet loggedInis. Ik moet het inlogformulier weergeven, anders dispatcheen actiondie de route zou veranderen en een ander onderdeel zou laden. Hier is mijn code:

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

Hoe kan ik dit bereiken, aangezien ik de status binnen de functie renderniet kan wijzigen.


Antwoord 1, autoriteit 100%

Aangezien je react-router v4

gebruikt

Gebruik je component met withRouteren gebruik history.pushvan props om de route te wijzigen. U hoeft alleen gebruik te maken van withRouterwanneer uw component de Router-props niet ontvangt. Dit kan gebeuren in gevallen waarin uw component een genest kind is van een component die wordt weergegeven door de Router en u hebt de Router-rekwisieten er niet aan doorgegeven of wanneer het onderdeel helemaal niet aan de Router is gekoppeld en wordt weergegeven als een afzonderlijk onderdeel van de Routes.

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);

Belangrijke opmerking

Als u withRoutergebruikt om te voorkomen dat updates worden geblokkeerd door
shouldComponentUpdate, is het belangrijk dat withRouterde
component dat shouldComponentUpdateimplementeert. Bijvoorbeeld, wanneer?
Redux gebruiken:

// Dit omzeilt shouldComponentUpdate

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

// Dit niet

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

of je zou Redirect kunnen gebruiken

import {withRouter} from 'react-router';
class App extends React.Component {
     ...
     render() {
         if(isLoggedIn) {
              return <Redirect to="/home"/>
         }
         // return login component
         return <Login />
    }
}

Met react-router v2 or react-router v3, kunt u gebruik maken van contextom de route dynamisch te wijzigen zoals

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;

of gebruik

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

Antwoord 2, autoriteit 12%

In react-router versie 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;

Antwoord 3, autoriteit 9%

Een ander alternatief is om dit af te handelen met behulp van asynchrone acties in Thunk-stijl (die veilig zijn/bijwerkingen mogen hebben).

Als je Thunk gebruikt, kun je hetzelfde history-object in zowel je <Router>-component als in de Thunk-acties injecteren met thunk.withExtraArgument, zoals dit:

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)

Dan heb je in je actie-creators een history-instantie die veilig te gebruiken is met ReactRouter, dus je kunt gewoon een normale Redux-gebeurtenis activeren als je niet bent ingelogd:

p>

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

Een ander voordeel hiervan is dat de url nu gemakkelijker te hanteren is, dus we kunnen omleidingsinformatie op de queryreeks plaatsen, enz.

Je kunt nog steeds proberen deze controle in je Render-methoden uit te voeren, maar als het problemen veroorzaakt, zou je kunnen overwegen om het in componentDidMountte doen, of ergens anders in de levenscyclus (hoewel ik ook de wens begrijp om vast te houden met staatloze functionele componenten!)

Je kunt nog steeds Redux en mapDispatchToPropsgebruiken om de maker van de actie in je comptonent te injecteren, dus je component is nog steeds maar losjes verbonden met Redux.


Antwoord 4, autoriteit 5%

Dit is mijn adres loggedIn. react-router v4

PrivateRoute is toegestaan ​​voer pathin als de gebruiker is ingelogd en sla het token op in localStorge

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

Definieer hier alle paden in uw app

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

Antwoord 5, autoriteit 2%

Degenen die problemen ondervinden bij het implementeren hiervan op react-router v4. Hier is een werkende oplossing om programmatisch door de react-app te navigeren.

geschiedenis.js

import createHistory from 'history/createBrowserHistory'
export default createHistory()

App.js OF Route.jsx. Geef geschiedenis door aan uw router.

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

Je kunt push()gebruiken om te navigeren.

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

Allen Dank aan deze opmerking: https://github.com / Reacttraining / reageer-router / problemen / 3498 # IssueComment-301057248

Other episodes