Bagaimana cara melakukan redirect ke rute lain dengan react-router?

102

Saya mencoba melakukan SEDERHANA menggunakan react-router ( versi ^ 1.0.3 ) untuk mengarahkan ke tampilan lain dan saya hanya lelah.

import React from 'react';
import {Router, Route, Link, RouteHandler} from 'react-router';


class HomeSection extends React.Component {

  static contextTypes = {
    router: PropTypes.func.isRequired
  };

  constructor(props, context) {
    super(props, context);
  }

  handleClick = () => {
    console.log('HERE!', this.contextTypes);
    // this.context.location.transitionTo('login');
  };

  render() {
    return (
      <Grid>
        <Row className="text-center">          
          <Col md={12} xs={12}>
            <div className="input-group">
              <span className="input-group-btn">
                <button onClick={this.handleClick} type="button">
                </button>
              </span>
            </div>
          </Col>
        </Row>
      </Grid>
    );
  }
};

HomeSection.contextTypes = {
  location() {
    React.PropTypes.func.isRequired
  }
}

export default HomeSection;

yang saya butuhkan hanyalah mengirim penggunaan ke '/ login' dan hanya itu.

Apa yang dapat saya ?

kesalahan di konsol:

ReferenceError Tidak Tertangkap: PropTypes tidak ditentukan

mengajukan dengan rute saya

// LIBRARY
/*eslint-disable no-unused-vars*/
import React from 'react';
/*eslint-enable no-unused-vars*/
import {Route, IndexRoute} from 'react-router';

// COMPONENT
import Application from './components/App/App';
import Contact from './components/ContactSection/Contact';
import HomeSection from './components/HomeSection/HomeSection';
import NotFoundSection from './components/NotFoundSection/NotFoundSection';
import TodoSection from './components/TodoSection/TodoSection';
import LoginForm from './components/LoginForm/LoginForm';
import SignupForm from './components/SignupForm/SignupForm';

export default (
    <Route component={Application} path='/'>
      <IndexRoute component={HomeSection} />
      <Route component={HomeSection} path='home' />
      <Route component={TodoSection} path='todo' />
      <Route component={Contact} path='contact' />
      <Route component={LoginForm} path='login' />
      <Route component={SignupForm} path='signup' />
      <Route component={NotFoundSection} path='*' />
    </Route>
);
Bereaksi
sumber
Hai! Dapatkah Anda memposting routesdefinisi Anda , dan juga jika ada alasan Anda tidak menggunakan Linkkomponen? Juga, sebutkan kesalahan apa yang Anda dapatkan.
aarosil
Bukan tombol <Link to="/login">Log In</Link>,?
aarosil
Juga versi react-router apa yang Anda gunakan? Kode untuk pengalihan prosedural telah berubah di antara versi utama.
mjhm
4
Untuk Uncaught ReferenceError, Anda memanggil sebagai PropTypes, tetapi Anda tidak mengimpornya, Anda perlu mengimpor PropTypes sebagai dirinya sendiri atau menggunakanReact.PropTypes
aarosil
1
@JoshDavidMiller bagus tapi saya tidak akan terkejut react-routerperubahan api dalam 5 menit .. haha ​​bercanda, tapi hanya sebagian
aarosil

Jawaban:

33

Untuk jawaban sederhananya, Anda dapat menggunakan Linkkomponen dari react-router, sebagai ganti button. Ada cara untuk mengubah rute di JS, tetapi sepertinya Anda tidak membutuhkannya di sini.

<span className="input-group-btn">
  <Link to="/login" />Click to login</Link>
</span>

Untuk melakukannya secara terprogram di 1.0.x, Anda melakukan seperti ini, di dalam fungsi clickHandler Anda:

this.history.pushState(null, 'login');

Diambil dari dokumen upgrade di sini

Anda harus sudah this.historymenempatkan komponen pengendali rute Anda pada react-router. Jika komponen anak di bawah yang disebutkan dalam routesdefinisi, Anda mungkin perlu meneruskannya lebih lanjut

aarosil.dll
sumber
2
ini adalah solusi yang keren, tetapi alasan mengapa saya tidak menggunakannya, adalah karena saya perlu melakukan semacam validasi terlebih dahulu, jadi saya perlu meletakkan ini dalam sebuah fungsi, seperti: if (true) { // redirect to login}jadi itulah mengapa saya meletakkannya di onClick fungsi
Bereaksi
5
Anda juga dapat melakukannya di BEJ: {validation && <Link to="/login" />Click to login</Link>}. Jika validasi salah, tidak ada yang akan dirender.
aarosil
Saya tahu apa yang Anda maksud, tetapi saya perlu tombol untuk berada di sana, jika validasi benar, maka alihkan, jika tidak, pesan kesalahan akan muncul.
Bereaksi
@TheUnnamed Saya memperbarui jawaban untuk menunjukkan bagaimana melakukannya di JS
aarosil
1
> TypeError Tidak Tertangkap: Tidak dapat membaca properti 'pushState' dari undefined
Bereaksi
109

1) react-router> useHistorykait V5 :

Jika Anda memiliki React >= 16.8dan komponen fungsional, Anda dapat menggunakan useHistory hook dari react-router .

import React from 'react';
import { useHistory } from 'react-router-dom';

const YourComponent = () => {
    const history = useHistory();

    const handleClick = () => {
        history.push("/path/to/push");
    }

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

export default YourComponent;

2) react-router> V4 withRouterHOC:

Seperti yang disebutkan @ambar dalam komentar, React-router telah mengubah basis kode mereka sejak V4 mereka. Berikut adalah dokumentasinya - official , withRouter

import React, { Component } from 'react';
import { withRouter } from "react-router-dom";

class YourComponent extends Component {
    handleClick = () => {
        this.props.history.push("path/to/push");
    }

    render() {
        return (
            <div>
                <button onClick={this.handleClick} type="button">
            </div>
        );
    };
}

export default withRouter(YourComponent);

3) React-router <V4 dengan browserHistory

Anda dapat mencapai fungsi ini menggunakan react-router BrowserHistory. Kode di bawah ini:

import React, { Component } from 'react';
import { browserHistory } from 'react-router';

export default class YourComponent extends Component {
    handleClick = () => {
        browserHistory.push('/login');
    };

    render() {
        return (
            <div>
                <button onClick={this.handleClick} type="button">
            </div>
        );
    };
}

4) Redux connected-react-router

Jika Anda telah menghubungkan komponen Anda dengan redux, dan telah mengkonfigurasi connected-react-router yang harus Anda lakukan adalah this.props.history.push("/new/url");, Anda tidak perlu withRouterHOC untuk menyuntikkan historyke props komponen.

// reducers.js
import { combineReducers } from 'redux';
import { connectRouter } from 'connected-react-router';

export default (history) => combineReducers({
    router: connectRouter(history),
    ... // rest of your reducers
});


// configureStore.js
import { createBrowserHistory } from 'history';
import { applyMiddleware, compose, createStore } from 'redux';
import { routerMiddleware } from 'connected-react-router';
import createRootReducer from './reducers';
...
export const history = createBrowserHistory();

export default function configureStore(preloadedState) {
    const store = createStore(
        createRootReducer(history), // root reducer with router state
        preloadedState,
        compose(
            applyMiddleware(
                routerMiddleware(history), // for dispatching history actions
                // ... other middlewares ...
            ),
        ),
    );

    return store;
}


// set up other redux requirements like for eg. in index.js
import { Provider } from 'react-redux';
import { Route, Switch } from 'react-router';
import { ConnectedRouter } from 'connected-react-router';
import configureStore, { history } from './configureStore';
...
const store = configureStore(/* provide initial state if any */)

ReactDOM.render(
    <Provider store={store}>
        <ConnectedRouter history={history}>
            <> { /* your usual react-router v4/v5 routing */ }
                <Switch>
                    <Route exact path="/yourPath" component={YourComponent} />
                </Switch>
            </>
        </ConnectedRouter>
    </Provider>,
    document.getElementById('root')
);


// YourComponent.js
import React, { Component } from 'react';
import { connect } from 'react-redux';
...

class YourComponent extends Component {
    handleClick = () => {
        this.props.history.push("path/to/push");
    }

    render() {
        return (
          <div>
            <button onClick={this.handleClick} type="button">
          </div>
        );
      }
    };

}

export default connect(mapStateToProps = {}, mapDispatchToProps = {})(YourComponent);
Noushad
sumber
3
Sepertinya 'browserHistory' bukan lagi bagian dari react-router.
Ambar
BrowserRouter tidak memiliki fungsi push
johnnyodonnell
@ambar @johnnyodonnell react-router-domtidak
toinetoine
Ini jawaban terbaik. Anda harus menandai yang ini sebagai yang benar.
Solomon Bush
24

Bagaimana cara melakukan redirect ke rute lain dengan react-router?

Misalnya, ketika pengguna mengklik tautan, <Link to="/" />Click to route</Link>react-router akan mencari /dan Anda dapat menggunakan Redirect todan mengirim pengguna ke tempat lain seperti rute login.

Dari dokumen untuk ReactRouterTraining :

Merender <Redirect>akan mengarahkan ke lokasi baru. Lokasi baru akan menimpa lokasi saat ini dalam tumpukan riwayat, seperti yang dilakukan pengalihan sisi server (HTTP 3xx).

import { Route, Redirect } from 'react-router'

<Route exact path="/" render={() => (
  loggedIn ? (
    <Redirect to="/dashboard"/>
  ) : (
    <PublicHomePage/>
  )
)}/>

ke: string, URL tujuan pengalihan.

<Redirect to="/somewhere/else"/>

to: object, Sebuah lokasi untuk dialihkan.

<Redirect to={{
  pathname: '/login',
  search: '?utm=your+face',
  state: { referrer: currentLocation }
}}/>
jtlindsey
sumber
Solusi yang diberikan menimbulkan kesalahan <Redirect> elements are for router configuration only and should not be rendered.
t1gor
12

Solusi termudah untuk web!

Hingga saat ini 2020
dikonfirmasi bekerja dengan:

"react-router-dom": "^5.1.2"
"react": "^16.10.2"

Gunakan useHistory()kailnya!

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


export function HomeSection() {
  const history = useHistory();
  const goLogin = () => history.push('login');

  return (
    <Grid>
      <Row className="text-center">          
        <Col md={12} xs={12}>
          <div className="input-group">
            <span className="input-group-btn">
              <button onClick={goLogin} type="button" />
            </span>
          </div>
        </Col>
      </Row>
    </Grid>
  );
}
Scott Plunkett
sumber
Luar biasa, sedang mencari cara yang tepat untuk melakukannya! Meskipun IDE saya menyatakan peringatan "Tidak dapat menyelesaikan simbol ...", itu berhasil!
Rafael Moni
Bagus, itulah yang saya cari dan berhasil di sini
nanquim
7

Dengan react-router v2.8.1 (mungkin versi 2.xx lainnya juga, tetapi saya belum mengujinya), Anda dapat menggunakan implementasi ini untuk melakukan pengalihan Router.

import { Router } from 'react-router';

export default class Foo extends Component {

  static get contextTypes() {
    return {
      router: React.PropTypes.object.isRequired,
    };
  }

  handleClick() {
    this.context.router.push('/some-path');
  }
}
Tom Van Rompaey
sumber
terkadang: this.context.router.history.push ('/ some-path');
象 嘉 道
5

Solusi paling sederhana adalah:

import { Redirect } from 'react-router';

<Redirect to='/componentURL' />
Jackkobec
sumber
Tapi saya mendapatkan Kesalahan: Invarian gagal: Anda tidak boleh menggunakan <Redirect> di luar <Router>
Prateek Gupta
Apakah Anda mencoba membungkusnya?
Jackkobec