วิธีใช้ Redirect ใน react-router-dom ใหม่ของ Reactjs


132

ฉันใช้โมดูล react-router เวอร์ชันล่าสุดชื่อ react-router-dom ซึ่งกลายเป็นค่าเริ่มต้นเมื่อพัฒนาเว็บแอปพลิเคชันด้วย React ฉันต้องการทราบวิธีการเปลี่ยนเส้นทางหลังจากคำขอ POST ฉันกำลังสร้างรหัสนี้ แต่หลังจากขอแล้วก็ไม่มีอะไรเกิดขึ้น ฉันตรวจสอบบนเว็บ แต่ข้อมูลทั้งหมดเกี่ยวกับเราเตอร์การตอบสนองเวอร์ชันก่อนหน้าและไม่มีในการอัปเดตครั้งล่าสุด

รหัส:

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
ของคุณRedirectดูเหมือน JSX ไม่ใช่ JS
elmeister

คุณช่วยให้รหัสส่วนประกอบทั้งหมดแก่คุณได้ไหม
KornholioBeavis

ใช่ฉันใช้ JSX บางทีฉันอาจจะต้องชี้แจง คำขอ POST อยู่ภายในส่วนประกอบ REACT ที่สร้างคำขอ
maoooricio

@KornholioBeavis แน่นอนตอนนี้คุณสามารถดูสมบูรณ์ ฉันสร้างเซิร์ฟเวอร์ด้วย expressjs ฉันไม่รู้ว่าคุณต้องการข้อมูลนี้หรือไม่
maoooricio

คุณตรวจสอบได้ไหมว่าคุณได้รับการตอบกลับจาก axios.post ทำไมคุณถึงใช้ฟังก์ชัน async โดยไม่ต้องรอที่ไหน
KornholioBeavis

คำตอบ:


199

คุณต้องใช้setStateเพื่อตั้งค่าคุณสมบัติที่จะแสดงผล<Redirect>ภายในrender()วิธีการของคุณ

เช่น

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

คุณยังสามารถดูตัวอย่างได้ในเอกสารอย่างเป็นทางการ: https://reacttraining.com/react-router/web/example/auth-workflow


ที่กล่าวว่าฉันขอแนะนำให้คุณใส่การเรียก API ภายในบริการหรือบางสิ่งบางอย่าง จากนั้นคุณก็สามารถใช้historyวัตถุเพื่อกำหนดเส้นทางโดยใช้โปรแกรม นี่คือวิธีการทำงานร่วมกับ Reduxงาน

แต่ฉันเดาว่าคุณมีเหตุผลที่จะทำแบบนี้


1
@sebastian sebald คุณหมายถึงอะไร: put the API call inside a service or something?
andrea-f

1
การมีการเรียก API (async) ดังกล่าวภายในส่วนประกอบของคุณจะทำให้ยากต่อการทดสอบและใช้ซ้ำ มันเป็นเรื่องปกติที่ดีคือการสร้างบริการแล้วใช้มัน (ตัวอย่าง) componentDidMountใน หรือที่ดีกว่านั้นคือสร้างHOCที่ "รวม" API ของคุณ
Sebastian Sebald

6
โปรดทราบว่าคุณต้องรวมการเปลี่ยนเส้นทางเพื่อใช้ในไฟล์เริ่มต้น: นำเข้า {Redirect} จาก 'react-router-dom'
Alex

3
ใช่ใต้ฝากระโปรงRedirectโทรhistory.replaceมา หากคุณต้องการเข้าถึงhistoryobect ใช้/withRoutet Route
เซบาสเตียนเซบาลด์

1
react-router> = 5.1 ตอนนี้มีตะขอดังนั้นคุณสามารถทำได้const history = useHistory(); history.push("/myRoute")
TheDarkIn1978

34

ต่อไปนี้เป็นตัวอย่างเล็ก ๆ น้อย ๆ สำหรับการตอบสนองต่อชื่อเรื่องเนื่องจากตัวอย่างที่กล่าวมาทั้งหมดมีความซับซ้อนในความคิดของฉันเช่นเดียวกับตัวอย่างที่เป็นทางการ

คุณควรรู้วิธีการ Transpile es2015 รวมถึงทำให้เซิร์ฟเวอร์ของคุณสามารถจัดการกับการเปลี่ยนเส้นทางได้ นี่คือตัวอย่างข้อมูลด่วน ข้อมูลเพิ่มเติมเกี่ยวกับนี้สามารถพบได้ที่นี่

อย่าลืมใส่ไว้ด้านล่างเส้นทางอื่น ๆ ทั้งหมด

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

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

นี่คือไฟล์. jsx สังเกตว่าเส้นทางที่ยาวที่สุดมาก่อนและกว้างขึ้นอย่างไร สำหรับเส้นทางทั่วไปส่วนใหญ่ให้ใช้แอตทริบิวต์ที่แน่นอน

// 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
สิ่งนี้ใช้ไม่ได้ตลอดเวลา หากคุณมีการเปลี่ยนเส้นทางจากhome/hello> home/hello/1แต่ไปที่home/helloและกด Enter จะไม่เปลี่ยนเส้นทางในครั้งแรก ไอเดียทำไม ??
The Walrus

ฉันแนะนำให้คุณใช้ "create-react-app" ถ้าเป็นไปได้และทำตามเอกสารจาก react-router ด้วย "create-react-app" ทุกอย่างทำงานได้ดีสำหรับฉัน ฉันไม่สามารถปรับแอปพลิเคชันการตอบสนองของตัวเองเป็นเราเตอร์ใหม่ได้
Matthis Kohli


8

React Router v5 ตอนนี้ช่วยให้คุณสามารถเปลี่ยนเส้นทางโดยใช้ history.push () ได้โดยใช้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>
  )
}

6

ลองอะไรแบบนี้

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;

มันได้ผล! ขอบคุณมาก นี่เป็นอีกวิธีหนึ่งในการทำเช่นนี้
maoooricio

คุณไม่ควรส่งคำขอ HTTP ในไฟล์คอมโพเนนต์ของคุณ
Kermit_ice_tea

คุณสามารถแบ่งปันสิ่งที่อยู่ในการนำเข้า SignUpForm จาก '../../register/components/SignUpForm'; ฉันพยายามเรียนรู้จากสิ่งนี้ แม้ว่าในกรณีของฉันฉันกำลังใช้แบบฟอร์ม redux
Temi 'Topsy' Bello

3

withRouterหรือคุณสามารถใช้ คุณสามารถได้รับการเข้าถึงhistoryคุณสมบัติของวัตถุและใกล้เคียงที่สุด<Route>'s matchผ่านwithRouterองค์ประกอบการสั่งซื้อที่สูงขึ้น withRouterจะผ่านการปรับปรุงmatch, locationและhistoryอุปกรณ์ประกอบฉากองค์ประกอบห่อเมื่อใดก็ตามที่จะแสดงผล

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)

หรือเพียงแค่:

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

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

1

คุณสามารถเขียน hoc เพื่อจุดประสงค์นี้และเขียน method call redirect นี่คือรหัส:

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"

สำหรับการสำรวจไปยังหน้าอื่น (หน้าเกี่ยวกับในกรณีของฉัน) prop-typesผมติดตั้ง จากนั้นฉันนำเข้าในส่วนประกอบที่เกี่ยวข้องและฉันใช้this.context.router.history.push('/about')และมันได้รับการนำทาง

รหัสของฉันคือ

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

เพื่อไปยังส่วนประกอบอื่นที่คุณสามารถใช้ได้ 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 พ่นคำเตือน: 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

วิธีที่ง่ายที่สุดในการไปยังส่วนประกอบอื่นคือ (ตัวอย่างนำทางไปยังส่วนประกอบอีเมลโดยคลิกที่ไอคอน):

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

0

หรือคุณสามารถใช้ 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>
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.