reactjs - helmet - react-router-dom




Navegue programaticamente usando o roteador react (19)

Com o react-router , posso usar o elemento Link para criar links que são nativamente tratados pelo roteador de reação.

Eu vejo internamente que chama this.context.transitionTo(...) .

Quero fazer uma navegação, mas não de um link, de uma seleção suspensa, por exemplo. Como posso fazer isso no código? O que é this.context ?

Vi o mix de Navigation , mas posso fazer isso sem mixins?


React Router V4

tl: dr;

if (navigate) {
  return <Redirect to="/" push={true} />
}

A resposta simples e declarativa é que você precisa usar <Redirect to={URL} push={boolean} /> em combinação com setState()

push: boolean - quando verdadeiro, o redirecionamento enviará uma nova entrada para o histórico em vez de substituir a atual.

import { Redirect } from 'react-router'

class FooBar extends React.Component {
  state = {
    navigate: false
  }

  render() {
    const { navigate } = this.state

    // here is the important part
    if (navigate) {
      return <Redirect to="/" push={true} />
    }
   // ^^^^^^^^^^^^^^^^^^^^^^^

    return (
      <div>
        <button onClick={() => this.setState({ navigate: true })}>
          Home
        </button>
      </div>
    )
  }
}

Exemplo completo here . Leia mais here .

PS. O exemplo usa inicializadores de propriedades do ES7 + para inicializar o estado. Olhe here também, se você estiver interessado.


Para o React Router v4 +

Supondo que você não precise navegar durante a renderização inicial em si (para a qual você pode usar o <Redirect> componente), é isso que estamos fazendo em nosso aplicativo.

Defina uma rota vazia que retorne nulo; isso permitirá que você obtenha acesso ao objeto histórico. Você precisa fazer isso no nível superior onde Router está definido.

Agora você pode fazer tudo o que pode ser feito na history history.push() , como history.replace() , history.go(-1) etc!

import React from 'react';
import { HashRouter, Route } from 'react-router-dom';

let routeHistory = null;

export function navigateTo(path) {
  if(routeHistory !== null) {
    routeHistory.push(path);
  }
}

export default function App(props) {
  return (
    <HashRouter hashType="noslash">
      <Route
        render={({ history }) => {
          routeHistory = history;
          return null;
        }}
      />
      {/* Rest of the App */}
    </HashRouter>
  );
}

Aviso: esta resposta cobre apenas as versões ReactRouter anteriores à 1.0

Atualizarei esta resposta com os casos de uso 1.0.0-rc1 depois!

Você pode fazer isso sem mixins também.

let Authentication = React.createClass({
  contextTypes: {
    router: React.PropTypes.func
  },
  handleClick(e) {
    e.preventDefault();
    this.context.router.transitionTo('/');
  },
  render(){
    return (<div onClick={this.handleClick}>Click me!</div>);
  }
});

O problema com os contextos é que ele não está acessível, a menos que você defina os contextTypes na classe.

Quanto ao contexto, é um objeto, como adereços, que é transmitido de pai para filho, mas é transmitido implicitamente, sem precisar redefinir adereços a cada vez. Consulte https://www.tildedave.com/2014/11/15/introduction-to-contexts-in-react-js.html


React Router v4

Com a v4 do React Router, há três abordagens que você pode adotar para o roteamento programático dentro dos componentes.

  1. Use o componente de ordem superior withRouter .
  2. Use a composição e renderize um <Route>
  3. Use o context .

O React Router é principalmente um invólucro em torno da biblioteca de history . history lida com a interação com a window.history do navegador.history para você com o histórico de hash e navegador. Ele também fornece um histórico de memória que é útil para ambientes que não possuem um histórico global. Isso é particularmente útil no desenvolvimento de aplicativos para dispositivos móveis ( react-native ) e no teste de unidade com o Node.

Uma instância do history possui dois métodos para navegar: push e replace . Se você pensar no history como uma matriz de locais visitados, o push adicionará uma nova localização à matriz e a replace substituirá a localização atual na matriz pela nova. Normalmente, você desejará usar o método push quando estiver navegando.

Nas versões anteriores do React Router, era necessário criar sua própria instância de history , mas na v4 os <BrowserRouter> , <HashRouter> e <MemoryRouter> criarão instâncias de navegador, hash e memória para você. O React Router disponibiliza as propriedades e os métodos da instância de history associada ao seu roteador por meio do contexto, sob o objeto do router .

1. Use o componente de ordem superior withRouter

O componente de ordem superior withRouter injeta o objeto de history como um suporte do componente. Isso permite acessar os métodos push e replace sem precisar lidar com o context .

import { withRouter } from 'react-router-dom'
// this also works with react-router-native

const Button = withRouter(({ history }) => (
  <button
    type='button'
    onClick={() => { history.push('/new-location') }}
  >
    Click Me!
  </button>
))

2. Use a composição e renderize um <Route>

O componente <Route> não é apenas para locais correspondentes. Você pode renderizar uma rota sem caminho e ela sempre corresponderá à localização atual . O componente <Route> passa os mesmos adereços que o withRouter , para que você possa acessar os métodos de history por meio do suporte de history .

import { Route } from 'react-router-dom'

const Button = () => (
  <Route render={({ history}) => (
    <button
      type='button'
      onClick={() => { history.push('/new-location') }}
    >
      Click Me!
    </button>
  )} />
)

3. Use o contexto *

Mas você provavelmente não deveria

A última opção é aquela que você deve usar apenas se sentir-se confortável trabalhando com o modelo de context do React. Embora o contexto seja uma opção, deve-se enfatizar que o contexto é uma API instável e o React possui uma seção Por que não usar o contexto em sua documentação. Portanto, use por sua conta e risco!

const Button = (props, context) => (
  <button
    type='button'
    onClick={() => {
      // context.history.push === history.push
      context.history.push('/new-location')
    }}
  >
    Click Me!
  </button>
)

// you need to specify the context type so that it
// is available within the component
Button.contextTypes = {
  history: React.PropTypes.shape({
    push: React.PropTypes.func.isRequired
  })
}

1 e 2 são as escolhas mais simples de implementar; portanto, na maioria dos casos de uso, são as suas melhores apostas.


React-Router v2

Para a versão mais recente ( v2.0.0-rc5 ), o método de navegação recomendado é empurrar diretamente para o singleton do histórico. Você pode ver isso em ação no documento Navegando fora dos componentes .

Trecho relevante:

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

Se estiver usando a API mais recente do this.props -router, você precisará fazer uso do history this.props quando estiver dentro dos componentes, para:

this.props.history.push('/some/path');

Ele também oferece pushState mas isso é preterido por avisos registrados.

Se estiver usando o react-router-redux , ele oferece uma função push você pode despachar da seguinte maneira:

import { push } from 'react-router-redux';
this.props.dispatch(push('/some/path'));

No entanto, isso pode ser usado apenas para alterar o URL, não para realmente navegar para a página.


Resposta do React-Router 4.x:

No final, gosto de ter um único objeto histórico que possa transportar até componentes externos. O que eu gosto de fazer é ter um único arquivo history.js que importo sob demanda e apenas o manipulo.

Você apenas precisa alterar o BrowserRouter para o Roteador e especificar o suporte do histórico. Isso não muda nada para você, exceto que você tem seu próprio objeto de histórico que você pode manipular como quiser.

Você precisa instalar o history , a biblioteca usada pelo react-router .

Exemplo de uso, notação ES6:

history.js

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

BasicComponent.js

import React, { Component } from 'react';
import history from './history';

class BasicComponent extends Component {

    goToIndex(e){
        e.preventDefault();
        history.push('/');
    }

    render(){
        return <a href="#" onClick={this.goToIndex}>Previous</a>;
    }
}

EDIT 16 de abril de 2018:

Se você precisar navegar a partir de um componente que é realmente renderizado a partir de um componente Route , também poderá acessar o histórico a partir de adereços, assim:

BasicComponent.js

import React, { Component } from 'react';

class BasicComponent extends Component {

    navigate(e){
        e.preventDefault();
        this.props.history.push('/url');
    }

    render(){
        return <a href="#" onClick={this.navigate}>Previous</a>;
    }
}

Aqueles que estão enfrentando problemas ao implementá-lo no react-router v4.

Aqui está uma solução funcional para navegar pelo aplicativo de reação a partir de ações de redux.

history.js

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

App.js / Route.jsx

import history from './history' 

history.push('/test') // this should change the url and re-render Test component

another_file.js OU arquivo redux

dispatch(navigateTo("/aboutUs"));

Tudo graças a este comentário: ReactTraining issues comment


Basta usar this.props.history.push('/where/to/go');


React-Router V4

se você estiver usando a versão 4, poderá usar minha biblioteca (plugue Shameless), onde você simplesmente despacha uma ação e tudo funciona!

import createHistory from 'history/createBrowserHistory'

export default createHistory()

trippler


Se, por acaso, emparelhar RR4 com redux com react react-router-redux , use também as react-router-redux opções de ação de roteamento .

import { push, replace, ... } from 'react-router-redux'

class WrappedComponent extends React.Component {
  handleRedirect(url, replaceState = true) { 
    replaceState 
      ? this.props.dispatch(replace(url)) 
      : this.props.dispatch(push(url)) 
  }
  render() { ... }
}

export default connect(null)(WrappedComponent)

Se usar redux thunk / saga para gerenciar o fluxo assíncrono, importe os criadores da ação acima em ações redux e conecte-os a reagir componentes usando o mapDispatchToProps.


Com a versão atual do React (15.3), this.props.history.push('/location'); funcionou para mim, mas mostrou o seguinte aviso:

browser.js: 49 Aviso: [ props.history -router] props.history e context.history estão obsoletos. Por favor, use context.router .

e resolvi usando context.router assim:

import React from 'react';

class MyComponent extends React.Component {

    constructor(props) {
        super(props);
        this.backPressed = this.backPressed.bind(this);
    }

    backPressed() {
        this.context.router.push('/back-location');
    }

    ...
}

MyComponent.contextTypes = {
    router: React.PropTypes.object.isRequired
};

export default MyComponent;

Eu tentei pelo menos 10 maneiras de fazer isso antes que algo desse certo!

A resposta withRouter @Felipe Skinner foi um pouco esmagadora para mim, e eu não tinha certeza se queria criar novos nomes de classe "ExportedWithRouter".

Aqui está a maneira mais simples e limpa de fazer isso, por volta do atual React-Router 3.0.0 e ES6:

React-Router 3.xx com ES6:

import { withRouter } from 'react-router';

class Example extends React.Component {
   // use `this.props.router.push('/some/path')` here
};

// Export the decorated class
export default withRouter(Example);

ou, se não for sua classe padrão, exporte como:

withRouter(Example);
export { Example };

Observe que no 3.xx, o próprio componente <Link> está usando o router.push , para que você possa passar tudo o que passaria na tag <Link to= , como:

   this.props.router.push({pathname: '/some/path', query: {key1: 'val1', key2: 'val2'})'

Para este, que não controla o lado do servidor e, por isso, está usando o roteador hash v2:

Coloque seu history em um arquivo separado (por exemplo, app_history.js ES6):

import { useRouterHistory } from 'react-router'
import { createHashHistory } from 'history'
const appHistory = useRouterHistory(createHashHistory)({ queryKey: false });

export default appHistory;

E use-o em qualquer lugar!

Seu ponto de entrada para o react-router (app.js ES6):

import React from 'react'
import { render } from 'react-dom'
import { Router, Route, Redirect } from 'react-router'
import appHistory from './app_history'
...
const render((
  <Router history={appHistory}>
  ...
  </Router>
), document.querySelector('[data-role="app"]'));

Sua navegação dentro de qualquer componente (ES6):

import appHistory from '../app_history'
...
ajaxLogin('/login', (err, data) => {
  if (err) {
    console.error(err); // login failed
  } else {
    // logged in
    appHistory.replace('/dashboard'); // or .push() if you don't need .replace()
  }
})

Para fazer a navegação programaticamente, você precisa enviar um novo histórico para o props.history em seu component , para que algo assim possa fazer o trabalho por você:

//using ES6
import React from 'react';

class App extends React.Component {

  constructor(props) {
    super(props)
    this.handleClick = this.handleClick.bind(this)
  }

  handleClick(e) {
    e.preventDefault()
    /* Look at here, you can add it here */
    this.props.history.push('/redirected');
  }

  render() {
    return (
      <div>
        <button onClick={this.handleClick}>
          Redirect!!!
        </button>
      </div>
    )
  }
}

export default App;

Para usar o withRouter com um componente baseado em classe, tente algo como isto abaixo. Não se esqueça de alterar a instrução de exportação para usar com o withRouter :

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

class YourClass extends React.Component {
  yourFunction = () => {
    doSomeAsyncAction(() =>
      this.props.history.push('/other_location')
    )
  }

  render() {
    return (
      <div>
        <Form onSubmit={ this.yourFunction } />
      </div>
    )
  }
}

export default withRouter(YourClass);

Pode não ser a melhor abordagem, mas ... Usando o react-router v4, o seguinte TypeScript pode dar uma idéia para alguns.

No componente renderizado abaixo, por exemplo, LoginPage , o objeto router está acessível e basta chamar router.transitionTo('/homepage') para navegar.

O código de navegação foi retirado from .

"react-router": "^4.0.0-2", "react": "^15.3.1",

import Router from 'react-router/BrowserRouter';
import { History } from 'react-history/BrowserHistory';
import createHistory from 'history/createBrowserHistory';
const history = createHistory();

interface MatchWithPropsInterface {
  component: typeof React.Component,
  router: Router,
  history: History,
  exactly?: any,
  pattern: string
}

class MatchWithProps extends React.Component<MatchWithPropsInterface,any> {
  render() {
    return(
      <Match {...this.props} render={(matchProps) => (
             React.createElement(this.props.component, this.props)

        )}
       />
    )
  }
}

ReactDOM.render(
    <Router>
      {({ router }) => (
        <div>
          <MatchWithProps exactly pattern="/" component={LoginPage} router={router} history={history} />
          <MatchWithProps pattern="/login" component={LoginPage} router={router} history={history} />
          <MatchWithProps pattern="/homepage" component={HomePage} router={router} history={history} />
          <Miss component={NotFoundView} />
        </div>
      )}
    </Router>,

   document.getElementById('app')
);


Veja como fazer isso com o react-router v2.0.0 com ES6 . react-router se afastou dos mixins.

import React from 'react';

export default class MyComponent extends React.Component {
  navigateToPage = () => {
    this.context.router.push('/my-route')
  };

  render() {
    return (
      <button onClick={this.navigateToPage}>Go!</button>
    );
  }
}

MyComponent.contextTypes = {
  router: React.PropTypes.object.isRequired
}

com base na resposta anterior
de José Antonio Postigo e Ben Wheeler
a novidade? deve ser escrito em Texto Dactilografado
e o uso de decoradores
OU propriedade estática / campo

import * as React from "react";
import Component = React.Component;
import { withRouter } from "react-router";

export interface INavigatorProps {
    router?: ReactRouter.History.History;
}

/**
 * Note: goes great with mobx 
 * @inject("something") @withRouter @observer
 */
@withRouter
export class Navigator extends Component<INavigatorProps, {}>{
    navigate: (to: string) => void;
    constructor(props: INavigatorProps) {
        super(props);
        let self = this;
        this.navigate = (to) => self.props.router.push(to);
    }
    render() {
        return (
            <ul>
                <li onClick={() => this.navigate("/home")}>
                    Home
                </li>
                <li onClick={() => this.navigate("/about")}>
                    About
                </li>
            </ul>
        )
    }
}

/**
 * Non decorated 
 */
export class Navigator2 extends Component<INavigatorProps, {}> {

    static contextTypes = {
        router: React.PropTypes.object.isRequired,
    };

    navigate: (to: string) => void;
    constructor(props: INavigatorProps, context: any) {
        super(props, context);
        let s = this;
        this.navigate = (to) =>
            s.context.router.push(to);
    }
    render() {
        return (
            <ul>
                <li onClick={() => this.navigate("/home")}>
                    Home
                </li>
                <li onClick={() => this.navigate("/about")}>
                    About
                </li>
            </ul>
        )
    }
}

com qualquer npm instalado hoje. "react-router": "^ 3.0.0" e
"@ types / react-router": "^ 2.0.41"


Roteamento de reação simples:

Link para minha caixa de proteção de código. Ele tem alguns outros programas simples de reação-redux.





react-router