Reactjs'in yeni react-router-dom'unda Redirect nasıl kullanılır


132

React ile web uygulamaları geliştirirken varsayılan olan react-router-dom adlı son versiyon react-router modülünü kullanıyorum. Bir POST isteğinden sonra nasıl yeniden yönlendirme yapacağımı öğrenmek istiyorum. Bu kodu yapıyorum ama talepten sonra hiçbir şey olmuyor. İnternette inceliyorum, ancak tüm veriler react yönlendiricisinin önceki sürümleri hakkındadır ve son güncellemeyle hayır.

Kod:

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;

1
Kişisel RedirectJSX gibi görünüyor, JS değil.
elmeister

size bileşen kodunun tamamını sağlayabilir misiniz
KornholioBeavis

Evet, JSX kullanıyorum. Belki de açıklamam gerekiyor. POST isteği, isteği yapan bir REACT bileşeninin içindedir.
maoooricio

@KornholioBeavis, elbette, şimdi tamamlandığını görebilirsiniz. Sunucuyu expressjs ile yapıyorum, bu verilere ihtiyacınız olup olmadığını bilmiyorum
maoooricio

Axios.post'tan bir geri arama yanıtı aldığınızı doğrulayabilir misiniz? Ayrıca neden hiçbir yerde beklemeden zaman uyumsuz işlevi kullanıyorsunuz?
KornholioBeavis

Yanıtlar:


199

Yönteminizin içini setStateişleyecek bir özellik ayarlamak için kullanmanız gerekir .<Redirect>render()

Örneğin

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

Resmi belgelerde de bir örnek görebilirsiniz: https://reacttraining.com/react-router/web/example/auth-workflow


Bununla birlikte, API çağrısını bir hizmete veya başka bir şeye koymanızı öneririm. O zaman historynesneyi programlı olarak yönlendirmek için kullanabilirsiniz . Bu nasıl redux ile entegrasyon eserleri.

Ama sanırım bunu bu şekilde yapmak için nedenleriniz var.


1
@sebastian Sebald sen ne demek istiyorsunuz: put the API call inside a service or something?
andrea-f

1
Bileşeninizin içinde böyle bir (zaman uyumsuz) API çağrısına sahip olmak, test etmeyi ve yeniden kullanmayı zorlaştıracaktır. Genellikle bir hizmet oluşturmak ve sonra onu (örneğin) içinde kullanmak daha iyidir componentDidMount. Daha da iyisi, API'nizi "saran" bir HOC oluşturun .
Sebastian Sebald

6
Dosyanın başlangıcında kullanmak için Redirect'i eklemeniz gerektiğine dikkat edin: 'react-router-dom'dan {Redirect} içe aktarın
Alex

3
Evet, kaputun altında Redirectarıyor history.replace. historyObekte erişmek istiyorsanız , withRoutet/ kullanın Route.
Sebastian Sebald

1
react-router> = 5.1 artık kancalar içeriyor, böylece şunları yapabilirsinizconst history = useHistory(); history.push("/myRoute")
TheDarkIn1978

34

Burada, adı geçen tüm örnekler gibi başlığa yanıt olarak küçük bir örnek, hem resmi hem de benim görüşüme göre karmaşıktır.

Es2015'i nasıl aktaracağınızı ve sunucunuzun yeniden yönlendirmeyi nasıl yapacağını bilmelisiniz. İşte ekspres için bir pasaj. Bununla ilgili daha fazla bilgi bulunabilir burada bulabilirsiniz .

Bunu diğer tüm yolların altına koyduğunuzdan emin olun.

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

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

Bu .jsx dosyasıdır. En uzun yolun nasıl önce geldiğine ve daha genelleştiğine dikkat edin. En genel rotalar için tam özelliğini kullanın.

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

1
bu her zaman işe yaramıyor. home/hello> adresinden bir yönlendirmeniz varsa, home/hello/1ancak daha sonra gidin home/hellove enter tuşuna basın, ilk seferinde yeniden yönlendirmeyecektir. herhangi bir fikir neden?
mors

Mümkünse "create-react-app" kullanmanızı ve react-router'daki belgeleri takip etmenizi öneririm. "Create-react-app" ile her şey benim için iyi çalışıyor. Kendi react uygulamamı yeni react-router'a uyarlayamadım.
Matthis Kohli


8

React Router v5 artık useHistory () kancası sayesinde history.push () kullanarak basitçe yeniden yönlendirme yapmanıza izin veriyor :

import { useHistory } from "react-router"

function HomeButton() {
  let history = useHistory()

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

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

6

Bunun gibi bir şey dene.

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;

Çalışıyor !, çok teşekkür ederim. Bu, bunu yapmanın başka bir yoludur.
maoooricio

Bileşen dosyalarınızda HTTP istekleri
yapmamalısınız

'../../Register/components/SignUpForm'dan içe aktarma SignUpForm'un içinde ne olduğunu paylaşabilir misiniz? Bundan öğrenmeye çalışıyorum. Yine de benim durumumda bir redux formu kullanıyorum
Temi 'Topsy' Bello

3

Alternatif olarak kullanabilirsiniz withRouter. Sen erişebilirsiniz historynesnenin özellikleri ve en yakın <Route>'s matcharacılığıyla withRouteryüksek mertebeden bileşeni. withRoutergüncellenmiş geçiren edecek match, locationve historybu hale ne zaman sarılmış bileşene sahne.

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)

Ya da sadece:

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

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

1

bu amaçla bir hoc yazabilir ve bir yöntem çağrısı yönlendirmesi yazabilirsiniz, işte kod:

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;

1
"react": "^16.3.2",
"react-dom": "^16.3.2",
"react-router-dom": "^4.2.2"

Başka bir sayfaya gitmek için (Benim durumumda hakkında sayfası), yükledim prop-types. Sonra onu ilgili bileşene this.context.router.history.push('/about')aktarıyorum ve kullandım ve gezinmeye başlıyor.

Benim kodum,

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

0

Başka bir bileşene gitmek için kullanabileceğiniz 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

1
React bir uyarı atıyor: 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

Başka bir bileşene gitmenin en basit çözümü (Örnek, simgeye tıklayarak posta bileşenine gider):

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

0

Alternatif olarak, React koşullu oluşturmayı kullanabilirsiniz.

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>
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.