Verwendung von Redirect im neuen React-Router-Dom von Reactjs

131

Ich verwende das React-Router-Modul der letzten Version mit dem Namen React-Router-Dom, das bei der Entwicklung von Webanwendungen mit React zum Standard geworden ist. Ich möchte wissen, wie man nach einer POST-Anfrage eine Umleitung vornimmt. Ich habe diesen Code erstellt, aber nach der Anfrage passiert nichts. Ich überprüfe im Web, aber alle Daten beziehen sich auf frühere Versionen des Reaktionsrouters und nein, mit dem letzten Update.

Code:

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
quelle
1
Ihr RedirectAussehen wie JSX, nicht JS.
Elmeister
können Sie Ihnen den gesamten Komponentencode zur Verfügung stellen
KornholioBeavis
Ja, ich verwende JSX. Nun, vielleicht muss ich das klarstellen. Die POST-Anforderung befindet sich in einer REACT-Komponente, die die Anforderung stellt.
Maoooricio
@KornholioBeavis, klar, jetzt können Sie vollständig sehen. Ich mache den Server mit Expressjs, ich weiß nicht, ob Sie diese Daten benötigen
maoooricio
Können Sie überprüfen, ob Sie eine Rückrufantwort von axios.post erhalten? Warum verwenden Sie die Async-Funktion, ohne irgendwo zu warten?
KornholioBeavis

Antworten:

196

Sie müssen verwenden setState, um eine Eigenschaft festzulegen, die das <Redirect>Innere Ihrer render()Methode rendert.

Z.B

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

Ein Beispiel finden Sie auch in der offiziellen Dokumentation: https://reacttraining.com/react-router/web/example/auth-workflow


Trotzdem würde ich vorschlagen, dass Sie den API-Aufruf in einen Dienst oder etwas anderes einfügen. Dann können Sie das historyObjekt einfach zum programmgesteuerten Routen verwenden. So funktioniert die Integration mit Redux .

Aber ich denke, Sie haben Ihre Gründe, dies so zu tun.

Sebastian Sebald
quelle
1
@sebastian sebald was meinst du mit : put the API call inside a service or something?
andrea-f
1
Ein solcher (asynchroner) API-Aufruf in Ihrer Komponente erschwert das Testen und Wiederverwenden. In der Regel ist es besser, einen Dienst zu erstellen und ihn dann (zum Beispiel) in zu verwenden componentDidMount. Oder noch besser, erstellen Sie ein HOC , das Ihre API "umschließt".
Sebastian Sebald
6
Achten Sie darauf, dass Sie Redirect einschließen müssen, um es am Anfang der Datei zu verwenden: {Redirect} aus 'react-router-dom' importieren
Alex
3
Ja, unter der Haube Redirectruft history.replace. Wenn Sie Zugriff auf das historyObjekt wünschen, verwenden Sie withRoutet/ Route.
Sebastian Sebald
1
react-router> = 5.1 enthält jetzt Hooks, so dass Sie nurconst history = useHistory(); history.push("/myRoute")
TheDarkIn1978
34

Hier ist ein kleines Beispiel als Antwort auf den Titel wie alle genannten Beispiele meiner Meinung nach ebenso kompliziert wie das offizielle.

Sie sollten wissen, wie man es2015 transpiliert und Ihren Server in die Lage versetzt, die Umleitung zu verarbeiten. Hier ist ein Ausschnitt für Express. Weitere Informationen hierzu finden Sie hier .

Stellen Sie sicher, dass dies unter allen anderen Routen steht.

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

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

Dies ist die .jsx-Datei. Beachten Sie, wie der längste Pfad zuerst kommt und allgemeiner wird. Verwenden Sie für die allgemeinsten Routen das genaue Attribut.

// 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
quelle
1
das funktioniert nicht immer. Wenn Sie eine Weiterleitung von home/hello> haben, home/hello/1aber dann zu gehen home/hellound die Eingabetaste drücken, wird diese beim ersten Mal nicht umgeleitet. irgendwelche Ideen warum?
Das Walross
Ich rate Ihnen, wenn möglich "create-react-app" zu verwenden und die Dokumentation des React-Routers zu befolgen. Mit "create-react-app" funktioniert alles gut für mich. Ich konnte meine eigene Reaktionsanwendung nicht an einen neuen Reaktionsrouter anpassen.
Matthis Kohli
8

Mit React Router v5 können Sie jetzt dank des useHistory () - Hooks einfach mit history.push () umleiten :

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
quelle
6

Versuchen Sie so etwas.

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
quelle
Es funktioniert!, Vielen Dank. Dies ist ein anderer Weg, dies zu tun.
Maoooricio
Sie sollten keine HTTP-Anfragen in Ihren Komponentendateien stellen
Kermit_ice_tea
Können Sie mitteilen, was sich im Import von SignUpForm aus '../../register/components/SignUpForm' befindet? Ich versuche daraus zu lernen. In meinem Fall verwende ich jedoch ein Redux-Formular
Temi 'Topsy' Bello
3

Alternativ können Sie verwenden withRouter. Sie können den Zugriff auf das bekommen historyEigenschaften des Objekts und die nächstgelegenen <Route>‚s matchüber die withRouterübergeordnete Komponente. withRoutervergehen aktualisiert match, locationund historyRequisiten , um die eingewickelt Komponente , wenn es macht.

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)

Oder nur:

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

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

Sie können zu diesem Zweck ein Hoc schreiben und eine Methodenaufrufumleitung schreiben. Hier ist der Code:

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
quelle
1
"react": "^16.3.2",
"react-dom": "^16.3.2",
"react-router-dom": "^4.2.2"

Um zu einer anderen Seite zu navigieren (in meinem Fall Info-Seite), habe ich installiert prop-types. Dann importiere ich es in die entsprechende Komponente. Und ich habe verwendetthis.context.router.history.push('/about') Und habe es Und es wird navigiert.

Mein Code ist,

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
quelle
0

Um zu einer anderen Komponente zu navigieren, können Sie verwenden 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.
quelle
1
React wirft eine Warnung: Warning: Cannot update during an existing state transition (such as within Rendern). Render methods should be a pure function of props and state.
Robotron
0

Die einfachste Lösung, um zu einer anderen Komponente zu navigieren, ist (Beispiel: Navigieren Sie zur E-Mail-Komponente, indem Sie auf das Symbol klicken):

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

Alternativ können Sie das bedingte Rendern von React verwenden.

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
quelle