Navigasi terprogram menggunakan router reaksi

1431

Dengan react-routersaya dapat menggunakan Linkelemen untuk membuat tautan yang secara asli ditangani oleh router reaksi.

Saya melihat secara internal itu panggilan this.context.transitionTo(...).

Saya ingin melakukan navigasi. Bukan dari tautan, tetapi dari pilihan tarik turun (sebagai contoh). Bagaimana saya bisa melakukan ini dalam kode? Apa this.context?

Saya melihat Navigationmixin, tetapi bisakah saya melakukannya tanpa mixins?

George Mauer
sumber
26
@SergioTapia perlu diingat bahwa pertanyaan ini mengangkangi rilis besar router-reaksi, rilis besar React, DAN rilis besar javascript
George Mauer
5
Berikut ini tautan ke tutorial di dokumen resmi router reaksi v4: reacttraining.com/react-router/web/guides/scroll-restoration
chitzui
4
Anda dapat memeriksa jawaban ini stackoverflow.com/questions/44127739/…
Shubham Khatri
4
Saya senang Anda mendapat jawaban ini, tetapi saya sedih itu harus serumit ini. Menavigasi dalam aplikasi web harus mudah dan didokumentasikan dengan baik. VueJS membuatnya sepele. Setiap komponen mendapatkan instance router yang disuntikkan secara otomatis. Ada bagian yang jelas untuknya di dokumen mereka. router.vuejs.org/guide/essentials/navigation.html Saya suka Bereaksi untuk banyak hal, tapi kadang-kadang sangat rumit. </rant>
colefner
7
@ GeorgeMauer Anda benar. Bukan itu tujuan komunitas ini. Ini tentang menjawab pertanyaan, bukan bertengkar tentang kerangka kerja. Terima kasih atas pengingatnya.
Colefner

Jawaban:

1436

Bereaksi Router v5.1.0 dengan kait

Ada useHistorykait baru di React Router> 5.1.0 jika Anda menggunakan React> 16.8.0 dan komponen fungsional.

import { useHistory } from "react-router-dom";

function HomeButton() {
  const history = useHistory();

  function handleClick() {
    history.push("/home");
  }

  return (
    <button type="button" onClick={handleClick}>
      Go home
    </button>
  );
}

Bereaksi Router v4

Dengan v4 dari React Router, ada tiga pendekatan yang dapat Anda ambil untuk routing terprogram dalam komponen.

  1. Gunakan komponen withRoutertingkat tinggi.
  2. Gunakan komposisi dan render a <Route>
  3. Gunakan context.

React Router sebagian besar adalah pembungkus di sekitar historyperpustakaan. historymenangani interaksi dengan browser window.historyuntuk Anda dengan browser dan riwayat hash. Ini juga menyediakan riwayat memori yang berguna untuk lingkungan yang tidak memiliki riwayat global. Ini sangat berguna dalam pengembangan aplikasi seluler (react-native ) dan pengujian unit dengan Node.

Sebuah historyinstance memiliki dua metode untuk navigasi: pushdan replace. Jika Anda menganggap historyarray sebagai lokasi yang dikunjungi, pushakan menambahkan lokasi baru ke array dan replaceakan mengganti lokasi saat ini dalam array dengan yang baru. Biasanya Anda ingin menggunakanpush metode ini saat bernavigasi.

Dalam versi sebelumnya dari Bereaksi Router, Anda harus membuat sendiri historymisalnya, tapi di v4 yang <BrowserRouter>, <HashRouter>dan <MemoryRouter>komponen akan membuat browser, hash, dan contoh memori untuk Anda. React Router membuat properti dan metode historyinstance yang terkait dengan router Anda tersedia melalui konteks, di bawah routerobjek.

1. Gunakan komponen withRoutertingkat tinggi

Komponen withRoutertingkat tinggi akan menyuntikkan historyobjek sebagai penyangga komponen. Ini memungkinkan Anda untuk mengakses pushdan replacemetode tanpa harus berurusan dengan 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. Gunakan komposisi dan render a <Route>

The <Route>komponen tidak hanya untuk lokasi yang cocok. Anda dapat membuat rute tanpa jalur dan akan selalu cocok dengan lokasi saat ini . The <Route>komponen melewati alat peraga yang sama seperti withRouter, sehingga Anda akan dapat mengakses historymetode melalui historyprop.

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

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

3. Gunakan konteks *

Tapi Anda mungkin tidak seharusnya

Opsi terakhir adalah yang hanya boleh Anda gunakan jika Anda merasa nyaman bekerja dengan model konteks React (API Konteks React stabil pada v16).

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 dan 2 adalah pilihan paling sederhana untuk diterapkan, jadi untuk sebagian besar kasus penggunaan, itu adalah taruhan terbaik Anda.

Paul S
sumber
24
Saya mencoba menggunakan metode 1 dengan cara ini withRouter (({history}) => {console.log ("hhhhhhhh"); history.push ('/ taruhan')}); Tapi itu tidak pernah bekerja dengan router 4
Dmitry Malugin
57
APA!? Saya hanya bisa menggunakan withRouteralih-alih melewati historysemua komponen saya ?? Gahh saya harus menghabiskan lebih banyak waktu membaca dokumen ...
hellojeffhall
18
Bagaimana Anda bisa menjalankan history.push('/new-location')tanpa melampirkan perilaku itu ke Button atau elemen DOM lainnya?
Neil
4
throwing error asUnexpected use of 'history' no-restricted-globals
Pardeep Jain
18
contexttidak eksperimental lagi pada reaksi 16.
trysis
921

React-Router 5.1.0+ Answer (menggunakan kait dan Bereaksi> 16.8)

Anda dapat menggunakan useHistorypengait baru pada Komponen Fungsional dan secara terprogram menavigasi:

import { useHistory } from "react-router-dom";

function HomeButton() {
  let history = useHistory();
  // use history.push('/some/path') here
};

React-Router 4.0.0+ Jawab

Di 4.0 dan di atas, gunakan riwayat sebagai penyangga komponen Anda.

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

CATATAN: this.props.history tidak ada jika komponen Anda tidak dirender oleh <Route>. Anda harus menggunakannya <Route path="..." component={YourComponent}/>untuk memiliki this.props.history di YourComponent

React-Router 3.0.0+ Jawab

Di 3.0 dan di atas, gunakan router sebagai penyangga komponen Anda.

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

React-Router 2.4.0+ Jawab

Di 2.4 dan di atas, gunakan komponen urutan yang lebih tinggi untuk mendapatkan router sebagai penyangga komponen Anda.

import { withRouter } from 'react-router';

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

// Export the decorated class
var DecoratedExample = withRouter(Example);

// PropTypes
Example.propTypes = {
  router: React.PropTypes.shape({
    push: React.PropTypes.func.isRequired
  }).isRequired
};

React-Router 2.0.0+ Jawab

Versi ini kompatibel dengan 1.x sehingga tidak perlu Panduan Upgrade. Hanya melalui contoh-contoh harus cukup baik.

Yang mengatakan, jika Anda ingin beralih ke pola baru, ada modul browserHistory di dalam router yang dapat Anda akses

import { browserHistory } from 'react-router'

Sekarang Anda memiliki akses ke riwayat browser Anda, sehingga Anda dapat melakukan hal-hal seperti mendorong, mengganti, dll ... Seperti:

browserHistory.push('/some/path')

Bacaan lebih lanjut: Sejarah dan Navigasi


React-Router 1.xx Jawab

Saya tidak akan masuk ke detail pemutakhiran. Anda dapat membaca tentang itu di Panduan Upgrade

Perubahan utama tentang pertanyaan di sini adalah perubahan dari Navigasi mixin ke Riwayat. Sekarang ia menggunakan histori browserAPI untuk mengubah rute sehingga kami akan menggunakannyapushState() mulai sekarang.

Inilah contoh menggunakan Mixin:

var Example = React.createClass({
  mixins: [ History ],
  navigateToHelpPage () {
    this.history.pushState(null, `/help`);
  }
})

Perhatikan bahwa ini Historyberasal dari rackt / history proyek . Bukan dari React-Router itu sendiri.

Jika Anda tidak ingin menggunakan Mixin karena alasan tertentu (mungkin karena kelas ES6), maka Anda dapat mengakses riwayat yang Anda peroleh dari router this.props.history. Ini hanya akan dapat diakses untuk komponen yang diberikan oleh Router Anda. Jadi, jika Anda ingin menggunakannya dalam komponen anak apa pun, harus diturunkan sebagai atribut melaluiprops .

Anda dapat membaca lebih lanjut tentang rilis baru di mereka dokumentasi 1.0.x

Disini adalah halaman bantuan khusus tentang navigasi di luar komponen Anda

Ini merekomendasikan mengambil referensi history = createHistory()dan memanggilnya replaceState.

React-Router 0.13.x Jawab

Saya masuk ke masalah yang sama dan hanya bisa menemukan solusi dengan mixin Navigasi yang datang dengan router reaksi.

Begini cara saya melakukannya

import React from 'react';
import {Navigation} from 'react-router';

let Authentication = React.createClass({
  mixins: [Navigation],

  handleClick(e) {
    e.preventDefault();

    this.transitionTo('/');
  },

  render(){
    return (<div onClick={this.handleClick}>Click me!</div>);
  }
});

Saya bisa menelepon transitionTo() tanpa perlu mengakses.context

Atau Anda bisa mencoba ES6 mewah class

import React from 'react';

export default class Authentication extends React.Component {
  constructor(props) {
    super(props);
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick(e) {
    e.preventDefault();

    this.context.router.transitionTo('/');
  }

  render(){
    return (<div onClick={this.handleClick}>Click me!</div>);
  }
}

Authentication.contextTypes = {
  router: React.PropTypes.func.isRequired
};

Bereaksi-Router-Redux

Catatan: jika Anda menggunakan Redux, ada proyek lain yang disebut ReactRouter-Redux yang memberikan Redux binding untuk ReactRouter, menggunakan agak pendekatan yang sama yang Bereaksi-Redux tidak

React-Router-Redux memiliki beberapa metode yang tersedia yang memungkinkan untuk navigasi sederhana dari pembuat aksi dalam. Ini dapat sangat berguna bagi orang-orang yang memiliki arsitektur di React Native, dan mereka ingin memanfaatkan pola yang sama di React Web dengan overhead boilerplate yang minimal.

Jelajahi metode berikut:

  • push(location)
  • replace(location)
  • go(number)
  • goBack()
  • goForward()

Berikut ini adalah contoh penggunaan, dengan Redux-Thunk :

./actioncreators.js

import { goBack } from 'react-router-redux'

export const onBackPress = () => (dispatch) => dispatch(goBack())

./viewcomponent.js

<button
  disabled={submitting}
  className="cancel_button"
  onClick={(e) => {
    e.preventDefault()
    this.props.onBackPress()
  }}
>
  CANCEL
</button>
Felipe Skinner
sumber
3
Saya menggunakan v2.4.0tetapi pendekatan yang disebutkan tidak bekerja untuk saya, aplikasi saya tidak menghasilkan sama sekali dan output konsol: Uncaught TypeError: (0 , _reactRouter.withRouter) is not a functioninilah tautan ke posting SO saya: stackoverflow.com/questions/37306166/…
nburk
7
Ini harus menjadi jawaban yang diterima, yang diterima agak berantakan dan sangat tua. @ GiantElk Saya membuatnya berfungsi seperti yang dijelaskan dalam jawaban untuk versi 2.6.0.
JMac
2
Apakah pendekatan ini masih merupakan cara yang disarankan untuk versi 3.0.x? Banyak orang tampaknya menggunakan contextcara itu.
velop
6
di 4.0, this.props.history tidak ada. Apa yang sedang terjadi?
Nicolas S.Xu
4
@ NicolasS.Xu this.props.historytidak ada jika komponen Anda tidak dirender oleh <Route>. Anda harus menggunakan <Route path="..." component={YourComponent}/>untuk memiliki this.props.historydi YourComponent.
vogdb
508

React-Router v2

Untuk rilis terbaru ( v2.0.0-rc5), metode navigasi yang disarankan adalah dengan langsung mendorong ke singleton sejarah. Anda dapat melihat bahwa dalam tindakan di bagian Navigasi di luar komponen .

Kutipan yang relevan:

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

Jika menggunakan API reaksi-router yang lebih baru, Anda perlu memanfaatkan historydari this.propssaat di dalam komponen jadi:

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

Itu juga menawarkan pushStatetetapi itu usang per peringatan yang dicatat.

Jika menggunakan react-router-redux, ia menawarkan pushfungsi yang dapat Anda kirim seperti:

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

Namun ini hanya dapat digunakan untuk mengubah URL, bukan untuk benar-benar menavigasi ke halaman.

Polisi
sumber
15
Jangan lupa bahwa API yang lebih baru tidak menggunakan import { browserHistory } from './react-router'tetapi malah membuat riwayat menggunakan import createBrowserHistory from 'history/lib/createBrowserHistory'. Kemudian, Anda dapat mengakses historydari komponen alat peraga:this.props.history('/some/path')
Ricardo Pedroni
7
var browserHistory = require('react-router').browserHistory; browserHistory.goBack();
Bobby
7
react-router-redux pushhanya mengubah URL, tidak benar-benar mengubah halaman. Untuk melakukan keduanya, impor browserHistorydari react-routerdan gunakan browserHistory.push('/my-cool-path'). Sayangnya, ini tidak super mudah ditemukan. github.com/reactjs/react-router/blob/master/docs/guides/…
Andrew Samuelsen
4
Saya menggunakan this.props.history.push ('/') tetapi hanya URL yang diubah ... Tidak ada perutean aktual yang terjadi di sini. Apa yang saya lewatkan?
rgcalsaverini
2
Saya baru saja mengunggah pendapat saya tentang cara bernavigasi secarareact-router
terprogram
56

Begini cara Anda melakukan ini react-router v2.0.0dengan ES6 . react-routertelah pindah dari mixin.

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
}
Alex Miller
sumber
5
Saya percaya rekomendasi saat ini adalah menggunakan historysingleton seperti yang dinyatakan oleh @ Bob. Anda dapat menggunakan context.routertetapi Anda membuatnya sangat sulit untuk menguji unit komponen-komponen tersebut sebagai instantiating hanya komponen yang tidak akan memiliki ini dalam konteksnya.
George Mauer
2
@ GeorgeMauer Saya pikir ini tergantung pada di mana kode berjalan. Sesuai reaksi dokumen, penggunaan konteks.router disarankan jika dijalankan di server. github.com/reactjs/react-router/blob/master/upgrade-guides/…
KumarM
50

React-Router 4.x Jawab:

Pada akhirnya, saya ingin memiliki objek sejarah tunggal yang dapat saya bawa bahkan komponen luar. Yang ingin saya lakukan adalah memiliki satu file history.js yang saya impor sesuai permintaan, dan hanya memanipulasinya.

Anda hanya perlu mengubah BrowserRouterke Router, dan tentukan prop sejarah. Ini tidak mengubah apa pun untuk Anda kecuali bahwa Anda memiliki objek sejarah Anda sendiri yang dapat Anda manipulasi seperti yang Anda inginkan.

Anda perlu menginstal histori , perpustakaan yang digunakan oleh react-router.

Contoh penggunaan, notasi 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 April 2018:

Jika Anda harus menavigasi dari komponen yang sebenarnya dirender dari Routekomponen, Anda juga dapat mengakses riwayat dari alat peraga, seperti itu:

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>;
    }
}
Eric Martin
sumber
2
Kecuali Bereaksi Router docs memberitahu kami Anda tidak harus, untuk kebanyakan kasus, kebutuhan untuk menggunakan Routerbukan BrowserRouter. BrowserRoutermembuat dan memelihara historyobjek untuk Anda. Anda seharusnya tidak membuat default sendiri, hanya jika Anda ["membutuhkan integrasi yang dalam dengan alat manajemen negara seperti Redux."] Reacttraining.com/react-router/web/api/Router
bobbyz
2
Itu adalah sesuatu yang saya pelajari dari waktu ke waktu dan pengalaman. Walaupun biasanya merupakan praktik yang baik untuk menggunakan default this.props.history, saya belum menemukan solusi yang dapat membantu saya melakukan hal seperti itu di kelas yang bukan komponen atau alat lain yang tidak dibangun sebagai komponen Bereaksi yang Anda dapat menurunkan alat peraga. Terima kasih atas tanggapan Anda :)
Eric Martin
44

Untuk yang ini, yang tidak mengontrol sisi server dan karena ini menggunakan router hash v2:

Tempatkan riwayat Anda ke dalam file terpisah (mis. App_history.js ES6):

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

export default appHistory;

Dan gunakan di mana-mana!

Titik masuk Anda untuk 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"]'));

Navigasi Anda di dalam komponen apa pun (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()
  }
})
Alexey Volodko
sumber
1
Terima kasih. Mungkin saya melewatkan sesuatu. Apakah ini tidak sama persis dengan dua jawaban teratas?
George Mauer
2
Saat Anda menggunakan navigasi "hash", di "react-router" v2 Anda perlu menginstal modul "history" tambahan (jika Anda ingin menghindari permintaan hash yang aneh), dan alih-alih menggunakan browserHistory Anda perlu menggunakanRouterHistory (createHashHistory) ( {queryKey: false}). Ini adalah alasan utama mengapa saya memposting ini. Saya menunjukkan cara menavigasi dengan sejarah hash.
Alexey Volodko
1
Oh, begitu, Anda benar. Saya tidak lagi dalam proyek itu tetapi saya pikir cara yang lebih disukai adalah menggunakan historyuntuk kedua pendekatan sekarang
George Mauer
4
mengapa jawaban ini bukan yang terbaik? mengapa masuk semua masalah dengan Context atau HOC atau prototipe acara, mengapa tidak hanya mengimpor sejarah dan menggunakan di mana pun kita mau? hanya mencoba memahami pengorbanan
storm_buster
@storm_buster tidak ada tradeoff. Kami memiliki modul ES6 dan kami harus menggunakannya! Ini adalah contoh khas dari penggunaan alat Anda (bereaksi dalam kasus ini) untuk semuanya - bahkan untuk hal-hal yang Anda tidak ingin menggunakannya.
Capaj
40

Bereaksi Router V4

tl: dr;

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

Jawaban sederhana dan deklaratif adalah bahwa Anda harus menggunakan <Redirect to={URL} push={boolean} />dalam kombinasi dengansetState()

push: boolean - ketika benar, pengalihan akan mendorong entri baru ke dalam sejarah alih-alih menggantikan yang sekarang.


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

Contoh lengkap di sini . Baca lebih lanjut di sini .

PS. Contoh ini menggunakan ES7 + Properti Inisialisasi untuk menginisialisasi keadaan. Lihat di sini juga, jika Anda tertarik.

Lyubomir
sumber
Ini jawaban terbaik yang saya temukan. Menggunakan withRoutertidak berfungsi saat sudah berada di rute yang sedang dimuat ulang. Dalam kasus kami, kami harus selektif melakukan setState(menyebabkan return <Redirect>) jika sudah di rute atau history.push()dari tempat lain.
karmakaze
Sangat, sangat pintar. Namun sangat sederhana. Tks. Saya menggunakannya di dalam ReactRouterTable karena saya ingin menangani klik pada seluruh baris. Digunakan pada onRowClick untuk mengatur status. setState ({navigTo: "/ path /" + row.uuid});
Lovato
ini jawaban anti peluru.
Nitin Jadhav
31

Peringatan: jawaban ini hanya mencakup versi ReactRouter sebelum 1.0

Saya akan memperbarui jawaban ini dengan kasus penggunaan 1.0.0-rc1 setelah!

Anda dapat melakukannya tanpa mixin juga.

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

Gotcha dengan konteksnya adalah bahwa itu tidak dapat diakses kecuali jika Anda mendefinisikan contextTypesdi kelas.

Adapun apa konteksnya, itu adalah objek, seperti properti, yang diturunkan dari orangtua ke anak, tetapi diturunkan secara implisit, tanpa harus mendeklarasikan ulang properti setiap kali. Lihat https://www.tildedave.com/2014/11/15/introduction-to-contexts-in-react-js.html

Qiming
sumber
26

Saya mencoba setidaknya 10 cara untuk melakukan ini sebelum sesuatu berhasil!

Jawaban @Felipe Skinner withRouteragak berlebihan bagi saya, dan saya tidak yakin ingin membuat nama kelas "ExportedWithRouter" yang baru.

Inilah cara paling sederhana dan paling bersih untuk melakukannya, sekitar saat ini React-Router 3.0.0 dan ES6:

React-Router 3.xx dengan 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);

atau, jika bukan kelas default Anda, ekspor suka:

withRouter(Example);
export { Example };

Perhatikan bahwa pada 3.xx, <Link>komponen itu sendiri sedang digunakan router.push, sehingga Anda dapat memberikan apa pun yang Anda berikan pada <Link to=tag, seperti:

   this.props.router.push({pathname: '/some/path', query: {key1: 'val1', key2: 'val2'})'
Ben Wheeler
sumber
1
Ini bekerja dengan sangat baik. Tetapi merespons 200 OKbukannya 30xkode. Bagaimana saya bisa memperbaiki masalah ini?
Muhammad Ateeq Azam
1
Tidak yakin. Ini tidak pernah muncul untuk saya karena itu bukan permintaan eksternal - itu hanya browser Anda menggunakan kode halaman sendiri untuk mengubah apa yang ada di halaman. Anda selalu dapat melakukan pengalihan javascript manual jika diinginkan.
Ben Wheeler
1
itu juga dapat digunakan dengan @withRouter sebagai dekorator kelas ... sangat cocok dengan mobx
Dan
21

Untuk melakukan navigasi secara terprogram, Anda perlu mendorong riwayat baru ke props.history di Anda component, jadi sesuatu seperti ini dapat melakukan pekerjaan untuk Anda:

//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;
Alireza
sumber
Silakan tulis versi react-router
Ash
19

Untuk komponen ES6 + Bereaksi, solusi berikut ini bekerja untuk saya.

Saya mengikuti Felippe skinner, tetapi menambahkan solusi ujung ke ujung untuk membantu pemula seperti saya.

Di bawah ini adalah versi yang saya gunakan:

"react-router": "^ 2.7.0"

"reaksi": "^ 15.3.1"

Di bawah ini adalah komponen reaksi saya di mana saya menggunakan navigasi terprogram menggunakan react-router:

import React from 'react';

class loginComp extends React.Component {
   constructor( context) {
    super(context);
    this.state = {
      uname: '',
      pwd: ''
    };
  }

  redirectToMainPage(){
        this.context.router.replace('/home');
  }

  render(){
    return <div>
           // skipping html code 
             <button onClick={this.redirectToMainPage.bind(this)}>Redirect</button>
    </div>;
  }
};

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

 module.exports = loginComp;

Di bawah ini adalah konfigurasi untuk router saya:

 import { Router, Route, IndexRedirect, browserHistory } from 'react-router'

 render(<Router history={browserHistory}>
          <Route path='/' component={ParentComp}>
            <IndexRedirect to = "/login"/>
            <Route path='/login' component={LoginComp}/>
            <Route path='/home' component={HomeComp}/>
            <Route path='/repair' component={RepairJobComp} />
            <Route path='/service' component={ServiceJobComp} />
          </Route>
        </Router>, document.getElementById('root'));
Softwareddy
sumber
19

Mungkin bukan pendekatan terbaik tapi ... Menggunakan react-router v4, TypeScript berikut dapat memberikan ide bagi sebagian orang.

Dalam komponen yang diberikan di bawah ini, misalnya LoginPage, routerobjek dapat diakses dan hanya panggilan router.transitionTo('/homepage')untuk menavigasi.

Kode navigasi diambil dari .

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

mcku
sumber
1
Mengapa Anda tidak menggunakan withRouter dan browserHistory?
Erwin Mayer
1
@ Erwin API berbeda di v4. Lihat ini github.com/ReactTraining/react-router/issues/3847 .
mcku
1
@ mcku Dari mana Anda mendapatkan file dts naskah skrip Anda untuk react-router v4?
jmathew
1
@ jmathew Saya tidak punya definisi tipe apa pun untuk react-router v4
mcku
16

Di Bereaksi-Router v4 dan ES6

Anda bisa menggunakan withRouterdan this.props.history.push.

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

class Home extends Component {

    componentDidMount() {
        this.props.history.push('/redirect-to');
    }
}

export default withRouter(Home);
Hossein
sumber
2
Sudah disebutkan dalam beberapa jawaban lain (termasuk panjang di jawaban atas)
George Mauer
13

Untuk digunakan withRouterdengan komponen berbasis kelas, coba sesuatu seperti ini di bawah ini. Jangan lupa untuk mengubah pernyataan ekspor untuk digunakan 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);
Janos
sumber
11

berdasarkan jawaban sebelumnya
dari José Antonio Postigo dan Ben Wheeler
hal yang baru? harus ditulis dalam naskah
dan penggunaan dekorator
ATAU properti / bidang statis

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

dengan nPM apa pun yang diinstal hari ini. "react-router": "^ 3.0.0" dan
"@ types / react-router": "^ 2.0.41"

Dan
sumber
11

dengan React-Router v4 di cakrawala, sekarang ada cara baru untuk melakukan ini.

import { MemoryRouter, BrowserRouter } from 'react-router';

const navigator = global && global.navigator && global.navigator.userAgent;
const hasWindow = typeof window !== 'undefined';
const isBrowser = typeof navigator !== 'undefined' && navigator.indexOf('Node.js') === -1;
const Router = isBrowser ? BrowserRouter : MemoryRouter;

<Router location="/page-to-go-to"/>

react-lego adalah aplikasi contoh yang menunjukkan cara menggunakan / memperbarui router reaksi dan itu termasuk contoh tes fungsional yang menavigasi aplikasi.

peter.mouland
sumber
5
Ini bagus untuk menavigasi dari fungsi render, meskipun saya bertanya-tanya bagaimana cara menavigasi dari sesuatu seperti kait siklus hidup, atau redux?
Ruben Martinez Jr.
11

Dalam bereaksi router v4. Saya mengikuti dua cara ini untuk merutekan secara programatis.

1. this.props.history.push("/something/something")
2. this.props.history.replace("/something/something")

Nomor dua

Mengganti entri saat ini pada tumpukan riwayat

Untuk mendapatkan riwayat dalam alat peraga Anda mungkin harus membungkus komponen Anda dengan

denganRouter

saiful619945
sumber
Terima kasih!! Jawaban Terbaik
Taha Farooqui
9

Jika Anda menggunakan hash atau riwayat browser maka Anda dapat melakukannya

hashHistory.push('/login');
browserHistory.push('/login');
Zaman Afzal
sumber
2
hashHistory.push, memberi Cannot read properti "push" dari undefined. Dari mana Anda mengimpor ini?
ArchNoob
impor {hashHistory} dari "react-router"; Anda dapat mengimpornya dengan cara ini di bagian atas.
Zaman Afzal
Saya menggunakan contoh kode Anda dari file redux saga saya, mengimpor seperti yang Anda katakan dan menggunakannya tetapi saya tetap mendapatkan TypeError itu.
ArchNoob
8

Dengan versi Bereaksi saat ini (15.3), this.props.history.push('/location');berfungsi untuk saya, tetapi ini menunjukkan peringatan berikut:

browser.js: 49 Peringatan: [react-router] props.historydan context.historysudah tidak digunakan lagi. Silakan gunakan context.router.

dan saya menyelesaikannya menggunakan context.routerseperti ini:

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;
José Antonio Postigo
sumber
1
Ini bekerja untuk V4. Yah ... tutup ... ini harus berupa this.context.router.history.push ('/ back-location');
velohomme
7

React-Router V4

jika Anda menggunakan versi 4 maka Anda dapat menggunakan perpustakaan saya (plug Shameless) di mana Anda hanya mengirim tindakan dan semuanya hanya berfungsi!

dispatch(navigateTo("/aboutUs"));

trippler

Garry Taylor
sumber
5

Mereka yang menghadapi masalah dalam mengimplementasikan ini pada react-router v4.

Berikut adalah solusi yang berfungsi untuk menavigasi melalui aplikasi reaksi dari tindakan redux.

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>

another_file.js ATAU file redux

import history from './history' 

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

Semua berkat komentar ini: ReactTraining mengeluarkan komentar

refleksivitas
sumber
4

Jika kebetulan memasangkan RR4 dengan redux melalui react-router-redux , gunakan pembuat tindakan perutean dari react-router-reduxopsi juga.

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)

Jika menggunakan redux thunk / saga untuk mengelola aliran async, impor pembuat tindakan di atas dalam aksi redux dan kait untuk bereaksi komponen menggunakan mapDispatchToProps mungkin lebih baik.

Xlee
sumber
1
react-router-reduxtelah ditinggalkan / diarsipkan untuk waktu yang lama
oligofren
4

Anda juga dapat menggunakan useHistorypengait di komponen tanpa kewarganegaraan. Contoh dari dokumen.

import { useHistory } from "react-router"

function HomeButton() {
  const history = useHistory()

  return (
    <button type="button" onClick={() => history.push("/home")}>
      Go home
    </button>
  )
}

Catatan: Kait ditambahkan [email protected]dan dibutuhkanreact@>=16.8

Nickofthyme
sumber
1
Panggilan yang bagus, dapatkah Anda mencatat versi yang mereaksi router dan bereaksi yang merujuk? Ini adalah perubahan baru yang tidak selalu tersedia
George Mauer
3

Jawaban yang tepat bagi saya pada saat penulisan

this.context.router.history.push('/');

Tetapi Anda perlu menambahkan PropTypes ke komponen Anda

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

Jangan lupa untuk mengimpor PropTypes

import PropTypes from 'prop-types';
webmaster
sumber
Harap tulis versi router reaksi, dan apa yang Anda impor dari router reaksi
Ash
Tidak ada yang diimpor dan ini adalah versi "react-router": "^ 4.2.0"
webmaster
3

Mungkin bukan solusi terbaik tetapi menyelesaikan pekerjaan:

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

// create functional component Post
export default Post = () => (
    <div className="component post">

        <button className="button delete-post" onClick={() => {
            // ... delete post
            // then redirect, without page reload, by triggering a hidden Link
            document.querySelector('.trigger.go-home').click();
        }}>Delete Post</button>

        <Link to="/" className="trigger go-home hidden"></Link>

    </div>
);

Pada dasarnya, sebuah logika terkait dengan satu tindakan (dalam hal ini penghapusan posting) akan berakhir memanggil pemicu untuk redirect. Ini tidak ideal karena Anda akan menambahkan 'pemicu' simpul DOM ke markup Anda sehingga Anda dapat dengan mudah menyebutnya ketika dibutuhkan. Juga, Anda akan langsung berinteraksi dengan DOM, yang dalam komponen Bereaksi mungkin tidak diinginkan.

Namun, jenis pengalihan ini tidak sering diperlukan. Jadi satu atau dua ekstra, tautan tersembunyi di markup komponen Anda tidak akan terlalu sakit, terutama jika Anda memberi mereka nama yang bermakna.

neatsu
sumber
Bisakah Anda menjelaskan mengapa Anda akan menggunakan ini di atas solusi yang diterima?
George Mauer
Ini hanyalah solusi alternatif untuk masalah yang dibahas. Seperti yang telah dinyatakan, tidak ideal tetapi berfungsi dengan baik untuk pengalihan terprogram.
neatsu
2

Ini bekerja untuk saya, tidak perlu impor khusus:

<input 
  type="button" 
  name="back" 
  id="back" 
  class="btn btn-primary" 
  value="Back" 
  onClick={() => { this.props.history.goBack() }} 
/>
JJ_Coder4Hire
sumber
Tentu saja ini membutuhkan impor khusus - komponen Anda tidak historyditambahkan propsdengan sendirinya. Itu berasal dari HoC yang perlu Anda impor untuk menggunakan (komponen yang dikirim langsung oleh Routesecara otomatis dibungkus oleh HoC itu tetapi kemudian Anda perlu impor untuk Route...)
George Mauer
2

gunakan hookrouter sebagai gantinya, alternatif modern untuk bereaksi-router

https://www.npmjs.com/package/hookrouter

import { useRoutes, usePath, A} from "hookrouter";

untuk menjawab pertanyaan OP tentang menautkan melalui kotak pilih Anda dapat melakukannya:

navigate('/about');
StefanBob
sumber
FYI. Penulis sendiri menyebut perpustakaan ini "bukti konsep" dan tidak memiliki aktivitas selama hampir satu tahun (Juni 2019).
MEMark
@Memark itu karena sudah sempurna
StefanBob
Nah, 38 masalah terbuka, bersama dengan fakta bahwa versi 2.0 akan menjadi penulisan ulang lengkap menurut auther, mengatakan sebaliknya.
MEMark
1

Untuk Bereaksi Router v4 +

Dengan asumsi bahwa Anda tidak perlu menavigasi selama render awal itu sendiri (untuk itu Anda dapat menggunakan <Redirect>komponen), inilah yang kami lakukan di aplikasi kami.

Tentukan rute kosong yang mengembalikan null, ini akan memungkinkan Anda untuk mendapatkan akses ke objek sejarah. Anda perlu melakukan ini di tingkat atas di mana AndaRouter didefinisikan.

Sekarang Anda dapat melakukan semua hal yang bisa dilakukan pada sejarah seperti history.push(), history.replace(), history.go(-1)dll!

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>
  );
}
Aftab Khan
sumber
1

react-router-dom: 5.1.2

  • Situs ini memiliki 3 halaman, yang semuanya dirender secara dinamis di browser.

  • Meskipun halaman tidak pernah di-refresh, perhatikan bagaimana React Router membuat URL selalu terbarui saat Anda menavigasi situs. Ini menjaga riwayat browser, memastikan hal-hal seperti tombol kembali dan bookmark berfungsi dengan baik

  • Sebuah Beralih terlihat melalui semua elemen anak dan menjadikan yang pertama yang jalan dengan URL saat ini. Gunakan waktu kapan saja Anda memiliki banyak rute, tetapi Anda hanya ingin satu dari mereka untuk membuat sekaligus

import React from "react";
import {
  BrowserRouter as Router,
  Switch,
  Route,
  Link
} from "react-router-dom";



export default function BasicExample() {
  return (
    <Router>
      <div>
        <ul>
          <li>
            <Link to="/">Home</Link>
          </li>
          <li>
            <Link to="/about">About</Link>
          </li>
          <li>
            <Link to="/dashboard">Dashboard</Link>
          </li>
        </ul>

        <hr />

        <Switch>
          <Route exact path="/">
            <Home />
          </Route>
          <Route path="/about">
            <About />
          </Route>
          <Route path="/dashboard">
            <Dashboard />
          </Route>
        </Switch>
      </div>
    </Router>
  );
}

// You can think of these components as "pages"
// in your app.

function Home() {
  return (
    <div>
      <h2>Home</h2>
    </div>
  );
}

function About() {
  return (
    <div>
      <h2>About</h2>
    </div>
  );
}

function Dashboard() {
  return (
    <div>
      <h2>Dashboard</h2>
    </div>
  );
}```
GOVINDARAJ
sumber
Selamat datang di SO! Ketika Anda menjawab pertanyaan dengan begitu banyak jawaban, cobalah untuk menunjukkan manfaat dari Anda.
David García Bodego
Ini juga tidak menjawab pertanyaan yang bagaimana melakukannya secara terprogram dari imperatif js, bukan dengan markup.
George Mauer
1

Jadi dalam jawaban saya ada 3 cara berbeda untuk mengarahkan secara terprogram ke suatu rute. Beberapa solusi telah disajikan tetapi yang berikut ini hanya difokuskan untuk komponen fungsional dengan aplikasi demo tambahan.

Menggunakan versi berikut:

reaksi: 16.13.1

reaksi-dom: 16.13.1

react-router: 5.2.0

react-router-dom: 5.2.0

naskah: 3.7.2

Konfigurasi:

Jadi pertama-tama solusinya menggunakan HashRouter, dikonfigurasi sebagai berikut:

<HashRouter>
    // ... buttons for redirect

    <Switch>
      <Route exact path="/(|home)" children={Home} />
      <Route exact path="/usehistory" children={UseHistoryResult} />
      <Route exact path="/withrouter" children={WithRouterResult} />
      <Route exact path="/redirectpush" children={RedirectPushResult} />
      <Route children={Home} />
    </Switch>
</HashRouter>

Dari dokumentasi tentang <HashRouter>:

A <Router>yang menggunakan bagian hash dari URL (yaitu window.location.hash) untuk menjaga UI Anda sinkron dengan URL.

Solusi:

  1. Menggunakan <Redirect>untuk mendorong menggunakan useState:

Menggunakan dalam komponen fungsional ( RedirectPushActionkomponen dari repositori saya) yang dapat kita gunakan useStateuntuk menangani pengalihan. Bagian yang rumit adalah begitu pengalihan terjadi kita perlu mengatur redirectnegara kembali ke false. Dengan menggunakan setTimeOutdengan 0penundaan kami menunggu hingga Bereaksi berkomitmenRedirect untuk DOM kemudian mendapatkan kembali tombol untuk menggunakan waktu berikutnya.

Silakan temukan contoh saya di bawah ini:

const [redirect, setRedirect] = useState(false);
const handleRedirect = useCallback(() => {
    let render = null;
    if (redirect) {
        render = <Redirect to="/redirectpush" push={true} />

        // in order wait until commiting to the DOM
        // and get back the button for clicking next time
        setTimeout(() => setRedirect(false), 0);
    }
    return render;
}, [redirect]);

return <>
    {handleRedirect()}
    <button onClick={() => setRedirect(true)}>
        Redirect push
    </button>
</>

Dari <Redirect>dokumentasi:

Rendering a <Redirect>akan menavigasi ke lokasi baru. Lokasi baru akan mengesampingkan lokasi saat ini di tumpukan riwayat, seperti pengalihan sisi server (HTTP 3xx) lakukan.

  1. Menggunakan useHistorykait:

Dalam solusi saya ada komponen yang disebut UseHistoryActionyang mewakili yang berikut:

let history = useHistory();

return <button onClick={() => { history.push('/usehistory') }}>
    useHistory redirect
</button>

The useHistorykait memberi kita akses ke objek sejarah yang membantu kita pemrograman menavigasi atau perubahan rute.

  1. Menggunakan withRouter, dapatkan historydari props:

Dibuat satu komponen bernama WithRouterAction, ditampilkan sebagai berikut:

const WithRouterAction = (props:any) => {
    const { history } = props;

    return <button onClick={() => { history.push('/withrouter') }}>
        withRouter redirect
    </button>
}

export default withRouter(WithRouterAction);

Membaca dari withRouterdokumentasi:

Anda bisa mendapatkan akses ke historyproperti objek dan <Route>kecocokan terdekat melalui withRouterkomponen orde tinggi. withRouterakan lulus diperbarui match,, locationdan historydisangga ke komponen yang dibungkus setiap kali dirender.

Demo:

Untuk representasi yang lebih baik, saya telah membangun repositori GitHub dengan contoh-contoh ini, silakan temukan di bawah ini:

https://github.com/norbitrial/react-router-programmatically-redirect-examples

Saya harap ini membantu!

norbitrial
sumber