Cara menggunakan Redirect di react-router-dom baru dari Reactjs

132

Saya menggunakan modul react-router versi terakhir, bernama react-router-dom, yang telah menjadi default saat mengembangkan aplikasi web dengan React. Saya ingin tahu cara melakukan pengalihan setelah permintaan POST. Saya telah membuat kode ini, tetapi setelah permintaan, tidak ada yang terjadi. Saya mengulas di web, tetapi semua data tentang versi sebelumnya dari router react, dan tidak dengan pembaruan terakhir.

Kode:

import React, { PropTypes } from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
import { Redirect } from 'react-router'

import SignUpForm from '../../register/components/SignUpForm';
import styles from './PagesStyles.css';
import axios from 'axios';
import Footer from '../../shared/components/Footer';

class SignUpPage extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      errors: {},
      client: {
        userclient: '',
        clientname: '',
        clientbusinessname: '',
        password: '',
        confirmPassword: ''
      }
    };

    this.processForm = this.processForm.bind(this);
    this.changeClient = this.changeClient.bind(this);
  }

  changeClient(event) {
    const field = event.target.name;
    const client = this.state.client;
    client[field] = event.target.value;

    this.setState({
      client
    });
  }

  async processForm(event) {
    event.preventDefault();

    const userclient = this.state.client.userclient;
    const clientname = this.state.client.clientname;
    const clientbusinessname = this.state.client.clientbusinessname;
    const password = this.state.client.password;
    const confirmPassword = this.state.client.confirmPassword;
    const formData = { userclient, clientname, clientbusinessname, password, confirmPassword };

    axios.post('/signup', formData, { headers: {'Accept': 'application/json'} })
      .then((response) => {
        this.setState({
          errors: {}
        });

        <Redirect to="/"/> // Here, nothings happens
      }).catch((error) => {
        const errors = error.response.data.errors ? error.response.data.errors : {};
        errors.summary = error.response.data.message;

        this.setState({
          errors
        });
      });
  }

  render() {
    return (
      <div className={styles.section}>
        <div className={styles.container}>
          <img src={require('./images/lisa_principal_bg.png')} className={styles.fullImageBackground} />
          <SignUpForm 
            onSubmit={this.processForm}
            onChange={this.changeClient}
            errors={this.state.errors}
            client={this.state.client}
          />
          <Footer />
        </div>
      </div>
    );
  }
}

export default SignUpPage;
maoooricio
sumber
1
Anda Redirecttampak seperti JSX, bukan JS.
elmeister
dapatkah Anda memberikan seluruh kode komponen
KornholioBeavis
Ya, saya menggunakan JSX. Mungkin saya perlu mengklarifikasi. Permintaan POST ada di dalam komponen REACT yang membuat permintaan tersebut.
maoooricio
@KornholBeavis, tentu, sekarang Anda bisa melihat lengkap. Saya membuat server dengan expressjs, saya tidak tahu apakah Anda memerlukan data ini
maoooricio
Dapatkah Anda memvalidasi bahwa Anda mendapatkan respons panggilan balik dari axios.post? Juga mengapa Anda menggunakan fungsi async tanpa menunggu di mana pun?
KornholioBeavis

Jawaban:

198

Anda harus menggunakan setStateuntuk menyetel properti yang akan merender di <Redirect>dalam render()metode Anda .

Misalnya

class MyComponent extends React.Component {
  state = {
    redirect: false
  }

  handleSubmit () {
    axios.post(/**/)
      .then(() => this.setState({ redirect: true }));
  }

  render () {
    const { redirect } = this.state;

     if (redirect) {
       return <Redirect to='/somewhere'/>;
     }

     return <RenderYourForm/>;
}

Anda juga dapat melihat contoh di dokumentasi resmi: https://reacttraining.com/react-router/web/example/auth-workflow


Karena itu, saya akan menyarankan Anda untuk menempatkan panggilan API di dalam layanan atau sesuatu. Kemudian Anda bisa menggunakan historyobjek untuk merutekan secara terprogram. Beginilah cara kerja integrasi dengan redux .

Tapi saya rasa Anda punya alasan untuk melakukannya dengan cara ini.

Sebastian Sebald
sumber
1
Sebald @sebastian apa yang Anda maksud dengan: put the API call inside a service or something?
andrea-f
1
Memiliki panggilan API (async) seperti itu di dalam komponen Anda akan mempersulit pengujian dan penggunaan kembali. Biasanya lebih baik membuat layanan lalu menggunakannya (misalnya) di componentDidMount. Atau lebih baik lagi, buat HOC yang "membungkus" API Anda.
Sebastian Sebald
6
Perhatikan bahwa Anda harus menyertakan Redirect untuk menggunakannya di awal file: import {Redirect} dari 'react-router-dom'
Alex
3
Ya, di bawah tenda Redirectmemanggil history.replace. Jika Anda ingin mengakses historyobjek, gunakan withRoutet/ Route.
Sebastian Sebald
1
react-router> = 5.1 sekarang termasuk hook, jadi Anda bisaconst history = useHistory(); history.push("/myRoute")
TheDarkIn1978
34

Berikut contoh kecil sebagai tanggapan atas judul karena semua contoh yang disebutkan rumit menurut saya dan juga yang resmi.

Anda harus tahu cara memindahkan es2015 serta membuat server Anda dapat menangani pengalihan. Berikut ini cuplikan untuk ekspres. Info lebih lanjut terkait hal ini dapat ditemukan di sini .

Pastikan untuk meletakkan ini di bawah semua rute lainnya.

const app = express();
app.use(express.static('distApp'));

/**
 * Enable routing with React.
 */
app.get('*', (req, res) => {
  res.sendFile(path.resolve('distApp', 'index.html'));
});

Ini adalah file .jsx. Perhatikan bagaimana jalur terpanjang didahulukan dan get lebih umum. Untuk rute yang paling umum, gunakan atribut yang tepat.

// Relative imports
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter, Route, Switch, Redirect } from 'react-router-dom';

// Absolute imports
import YourReactComp from './YourReactComp.jsx';

const root = document.getElementById('root');

const MainPage= () => (
  <div>Main Page</div>
);

const EditPage= () => (
  <div>Edit Page</div>
);

const NoMatch = () => (
  <p>No Match</p>
);

const RoutedApp = () => (
  <BrowserRouter >
    <Switch>
      <Route path="/items/:id" component={EditPage} />
      <Route exact path="/items" component={MainPage} />          
      <Route path="/yourReactComp" component={YourReactComp} />
      <Route exact path="/" render={() => (<Redirect to="/items" />)} />          
      <Route path="*" component={NoMatch} />          
    </Switch>
  </BrowserRouter>
);

ReactDOM.render(<RoutedApp />, root); 
Matthis Kohli
sumber
1
ini tidak selalu berhasil. jika Anda memiliki pengalihan dari home/hello> home/hello/1tetapi kemudian pergi ke home/hellodan tekan enter, itu tidak akan mengalihkan pertama kali. ada ide kenapa ??
The Walrus
Saya menyarankan Anda untuk menggunakan "create-react-app" jika memungkinkan dan ikuti dokumentasi dari react-router. Dengan "create-react-app" semuanya berfungsi dengan baik untuk saya. Saya tidak dapat menyesuaikan aplikasi react saya sendiri ke react-router baru.
Matthis Kohli
8

React Router v5 sekarang memungkinkan Anda untuk mengarahkan ulang menggunakan history.push () berkat hook useHistory () :

import { useHistory } from "react-router"

function HomeButton() {
  let history = useHistory()

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

  return (
    <button type="button" onClick={handleClick}>
      Go home
    </button>
  )
}
Thanh-Quy Nguyen
sumber
6

Cobalah sesuatu seperti ini.

import React, { PropTypes } from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
import { Redirect } from 'react-router'

import SignUpForm from '../../register/components/SignUpForm';
import styles from './PagesStyles.css';
import axios from 'axios';
import Footer from '../../shared/components/Footer';

class SignUpPage extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      errors: {},
      callbackResponse: null,
      client: {
        userclient: '',
        clientname: '',
        clientbusinessname: '',
        password: '',
        confirmPassword: ''
      }
    };

    this.processForm = this.processForm.bind(this);
    this.changeClient = this.changeClient.bind(this);
  }

  changeClient(event) {
    const field = event.target.name;
    const client = this.state.client;
    client[field] = event.target.value;

    this.setState({
      client
    });
  }

  processForm(event) {
    event.preventDefault();

    const userclient = this.state.client.userclient;
    const clientname = this.state.client.clientname;
    const clientbusinessname = this.state.client.clientbusinessname;
    const password = this.state.client.password;
    const confirmPassword = this.state.client.confirmPassword;
    const formData = { userclient, clientname, clientbusinessname, password, confirmPassword };

    axios.post('/signup', formData, { headers: {'Accept': 'application/json'} })
      .then((response) => {
        this.setState({
          callbackResponse: {response.data},
        });
      }).catch((error) => {
        const errors = error.response.data.errors ? error.response.data.errors : {};
        errors.summary = error.response.data.message;

        this.setState({
          errors
        });
      });
  }

const renderMe = ()=>{
return(
this.state.callbackResponse
?  <SignUpForm 
            onSubmit={this.processForm}
            onChange={this.changeClient}
            errors={this.state.errors}
            client={this.state.client}
          />
: <Redirect to="/"/>
)}

  render() {
    return (
      <div className={styles.section}>
        <div className={styles.container}>
          <img src={require('./images/lisa_principal_bg.png')} className={styles.fullImageBackground} />
         {renderMe()}
          <Footer />
        </div>
      </div>
    );
  }
}

export default SignUpPage;
KornholioBeavis
sumber
Berhasil !, terima kasih banyak. Ini adalah cara lain untuk melakukan ini.
maoooricio
Anda tidak boleh membuat permintaan HTTP dalam file komponen Anda
Kermit_ice_tea
Dapatkah Anda membagikan apa yang ada di dalam import SignUpForm dari '../../register/components/SignUpForm' ;? Saya mencoba belajar dari ini. Meskipun dalam kasus saya, saya menggunakan bentuk reduks
Temi 'Topsy' Bello
3

Alternatifnya, Anda bisa menggunakan withRouter. Anda bisa mendapatkan akses ke historyproperti obyek dan yang paling dekat <Route>'s matchmelalui withRouterkomponen tingkat tinggi. withRouterakan meneruskan update match,, locationdan historyprops ke komponen yang dibungkus setiap kali dirender.

import React from "react"
import PropTypes from "prop-types"
import { withRouter } from "react-router"

// A simple component that shows the pathname of the current location
class ShowTheLocation extends React.Component {
  static propTypes = {
    match: PropTypes.object.isRequired,
    location: PropTypes.object.isRequired,
    history: PropTypes.object.isRequired
  }

  render() {
    const { match, location, history } = this.props

    return <div>You are now at {location.pathname}</div>
  }
}
// Create a new component that is "connected" (to borrow redux
// terminology) to the router.
const ShowTheLocationWithRouter = withRouter(ShowTheLocation)

Atau hanya:

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

const Button = withRouter(({ history }) => (
  <button
    type='button'
    onClick={() => { history.push('/new-location') }}
  >
    Click Me!
  </button>
))
Ömürcan Cengiz
sumber
1

Anda dapat menulis hoc untuk tujuan ini dan menulis pengalihan panggilan metode, berikut kodenya:

import React, {useState} from 'react';
import {Redirect} from "react-router-dom";

const RedirectHoc = (WrappedComponent) => () => {
    const [routName, setRoutName] = useState("");
    const redirect = (to) => {
        setRoutName(to);
    };


    if (routName) {
        return <Redirect to={"/" + routName}/>
    }
    return (
        <>
            <WrappedComponent redirect={redirect}/>
        </>
    );
};

export default RedirectHoc;
zia
sumber
1
"react": "^16.3.2",
"react-dom": "^16.3.2",
"react-router-dom": "^4.2.2"

Untuk menavigasi ke halaman lain (Tentang halaman dalam kasus saya), saya menginstal prop-types. Kemudian saya mengimpornya di komponen yang sesuai. Dan saya menggunakanthis.context.router.history.push('/about') . Dan . Dan itu dinavigasi.

Kode saya adalah,

import React, { Component } from 'react';
import '../assets/mystyle.css';
import { Redirect } from 'react-router';
import PropTypes from 'prop-types';

export default class Header extends Component {   
    viewAbout() {
       this.context.router.history.push('/about')
    }
    render() {
        return (
            <header className="App-header">
                <div className="myapp_menu">
                    <input type="button" value="Home" />
                    <input type="button" value="Services" />
                    <input type="button" value="Contact" />
                    <input type="button" value="About" onClick={() => { this.viewAbout() }} />
                </div>
            </header>
        )
    }
}
Header.contextTypes = {
    router: PropTypes.object
  };
sojan
sumber
0

Untuk menavigasi ke komponen lain yang dapat Anda gunakan this.props.history.push('/main');

import React, { Component, Fragment } from 'react'

class Example extends Component {

  redirect() {
    this.props.history.push('/main')
  }

  render() {
    return (
      <Fragment>
        {this.redirect()}
      </Fragment>
    );
   }
 }

 export default Example
Morris S
sumber
1
React memberikan peringatan: Warning: Cannot update during an existing state transition (such as within render). Render methods should be a pure function of props and state.
Robotron
0

Solusi paling sederhana untuk menavigasi ke komponen lain adalah (Contoh menavigasi ke komponen email dengan mengklik ikon):

<MailIcon 
  onClick={ () => { this.props.history.push('/mails') } }
/>
Jackkobec
sumber
0

Alternatifnya, Anda dapat menggunakan React conditional rendering.

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

class UserSignup extends Component {
  constructor(props) {
    super(props);
    this.state = {
      redirect: false
    }
  }
render() {
 <React.Fragment>
   { this.state.redirect && <Redirect to="/signin" /> }   // you will be redirected to signin route
}
</React.Fragment>
}
Niyongabo
sumber