วิธีการผลักดันประวัติศาสตร์ใน React Router v4?


360

ใน React Router (v3) รุ่นปัจจุบันฉันสามารถยอมรับการตอบกลับของเซิร์ฟเวอร์และใช้browserHistory.pushเพื่อไปที่หน้าการตอบสนองที่เหมาะสม อย่างไรก็ตามนี่ไม่สามารถใช้ได้ใน v4 และฉันไม่แน่ใจว่าวิธีการที่เหมาะสมในการจัดการนี้คืออะไร

ในตัวอย่างนี้ใช้ Redux, ส่วนประกอบ / การตรวจสอบผลิตภัณฑ์ form.jsโทรthis.props.addProduct(props)เมื่อผู้ใช้ส่งแบบฟอร์ม เมื่อเซิร์ฟเวอร์กลับสู่ความสำเร็จผู้ใช้จะถูกนำไปที่หน้ารถเข็น

// actions/index.js
export function addProduct(props) {
  return dispatch =>
    axios.post(`${ROOT_URL}/cart`, props, config)
      .then(response => {
        dispatch({ type: types.AUTH_USER });
        localStorage.setItem('token', response.data.token);
        browserHistory.push('/cart'); // no longer in React Router V4
      });
}

ฉันจะเปลี่ยนเส้นทางไปยังหน้ารถเข็นจากฟังก์ชั่นสำหรับ React Router v4 ได้อย่างไร


เพียงเพิ่มจากสิ่งนี้จากโซลูชันล่าสุดที่เสนอและจากคำแนะนำในปัญหาของ React Router ใน GitHub การใช้contextเพื่อส่งผ่านสิ่งที่คุณต้องการด้วยตนเองคือ "ไม่ไป" หากฉันไม่ใช่ผู้แต่งห้องสมุดก็ไม่จำเป็นต้องใช้มัน ในความเป็นจริง Facebook แนะนำให้ต่อต้านมัน
Chris

@Chris คุณหาทางออกสำหรับสิ่งนี้หรือไม่? ฉันต้องการผลักดันให้มีการใช้งานส่วนประกอบที่แตกต่างกันเช่นเดียวกับที่คุณได้อธิบายไว้ที่นี่
Mr.G

@ Mr.G น่าเศร้าที่ฉันยังไม่ได้ สุดท้ายที่ฉันอ่านคือทีม React Training ที่ดูแล React Router ให้มีแพ็คเกจ redux ฉันไม่ได้มีโชคใด ๆ ทำให้มันทำงานและพวกเขาไม่ได้ทำงานมากในการแก้ไขมัน
Chris

ทำไมเราไม่สามารถใช้ windows.location.href = URL ได้ มีอะไรผิดปกติในการใช้มันเพื่อเปลี่ยน URL และเปลี่ยนเส้นทาง?
Shan

ฉันไม่เห็นว่าทำไมถึงไม่ แต่ตัวเลือกสำหรับการใช้historyยังทำงานได้กับ React Native เป็นตัวเลือกรวมถึงตัวเลือกเพิ่มเติมในการรองรับเบราว์เซอร์รุ่นเก่า
Chris

คำตอบ:


308

คุณสามารถใช้historyวิธีการนอกส่วนประกอบของคุณ ลองวิธีต่อไปนี้

ขั้นแรกให้สร้างhistoryวัตถุที่ใช้แพ็คเกจประวัติ :

// src/history.js

import { createBrowserHistory } from 'history';

export default createBrowserHistory();

จากนั้นห่อไว้ใน<Router>( โปรดทราบว่าคุณควรใช้import { Router }แทนimport { BrowserRouter as Router }):

// src/index.jsx

// ...
import { Router, Route, Link } from 'react-router-dom';
import history from './history';

ReactDOM.render(
  <Provider store={store}>
    <Router history={history}>
      <div>
        <ul>
          <li><Link to="/">Home</Link></li>
          <li><Link to="/login">Login</Link></li>
        </ul>
        <Route exact path="/" component={HomePage} />
        <Route path="/login" component={LoginPage} />
      </div>
    </Router>
  </Provider>,
  document.getElementById('root'),
);

เปลี่ยนตำแหน่งปัจจุบันของคุณจากที่ใดก็ได้ตัวอย่างเช่น:

// src/actions/userActionCreators.js

// ...
import history from '../history';

export function login(credentials) {
  return function (dispatch) {
    return loginRemotely(credentials)
      .then((response) => {
        // ...
        history.push('/');
      });
  };
}

UPD : คุณยังสามารถดูตัวอย่างที่แตกต่างกันเล็กน้อยในการตอบสนอง Router คำถามที่พบบ่อย


24
ฉันพยายามทำสิ่งที่ @OlegBelostotsky พูด แต่หลังจากhistory.push('some path')นั้น URL จะเปลี่ยนไป แต่หน้านั้นไม่เปลี่ยนแปลง ฉันต้องใส่window.location.reload()มันในบางส่วนของรหัสของฉันเพียงเพื่อให้มันทำงาน อย่างไรก็ตามในกรณีหนึ่งฉันต้องเก็บต้นไม้สถานะ redux และโหลดใหม่ทำลายมัน ทางออกอื่น ๆ ?
sdabrutas

2
@idunno ลองใช้withRouterส่วนประกอบลำดับสูงกว่า
Oleg Belostotsky

นี่ทำให้ฉันมีข้อผิดพลาดที่ระบุ: createBrowserHistory ไม่ใช่ฟังก์ชั่น ฉันจะทำอย่างไร
AKJ

@AKJ อาจimport createHistory from 'history/createBrowserHistory'; export default createHistory();จะใช้งานได้
Oleg Belostotsky

1
ขออภัยสำหรับ downvote :) ในขณะนี้ยังควรจะทำงานวิธีที่ถูกต้องในการจัดการนี้เป็นวิธีการที่คริสตอบ: stackoverflow.com/a/42716055/491075
gion_13

340

React Router v4 นั้นแตกต่างจาก v3 (และก่อนหน้านี้) และคุณไม่สามารถทำได้browserHistory.push()เหมือนที่เคยเป็นมา

ดูเหมือนว่าการสนทนานี้จะเกี่ยวข้องถ้าคุณต้องการข้อมูลเพิ่มเติม:

  • การสร้างใหม่browserHistoryจะไม่ทำงานเพราะ<BrowserRouter>สร้างอินสแตนซ์ประวัติของตนเองและรับฟังการเปลี่ยนแปลง ดังนั้นอินสแตนซ์ที่แตกต่างกันจะเปลี่ยน URL <BrowserRouter>แต่ไม่ปรับปรุง
  • browserHistory ไม่ได้ถูกแสดงโดย react-router ใน v4, เฉพาะใน v2

คุณมีตัวเลือกให้ทำดังนี้:

  • ใช้withRouterองค์ประกอบลำดับสูง

    แต่คุณควรใช้withRouterองค์ประกอบลำดับสูงและห่อที่องค์ประกอบที่จะผลักดันประวัติศาสตร์ ตัวอย่างเช่น:

    import React from "react";
    import { withRouter } from "react-router-dom";
    
    class MyComponent extends React.Component {
      ...
      myFunction() {
        this.props.history.push("/some/Path");
      }
      ...
    }
    export default withRouter(MyComponent);

    ตรวจสอบเอกสารอย่างเป็นทางการสำหรับข้อมูลเพิ่มเติม:

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


  • ใช้contextAPI

    การใช้บริบทอาจเป็นหนึ่งในโซลูชันที่ง่ายที่สุด แต่การใช้ API แบบทดลองนั้นไม่เสถียรและไม่รองรับ ใช้มันเฉพาะเมื่อทุกอย่างอื่นล้มเหลว นี่คือตัวอย่าง:

    import React from "react";
    import PropTypes from "prop-types";
    
    class MyComponent extends React.Component {
      static contextTypes = {
        router: PropTypes.object
      }
      constructor(props, context) {
         super(props, context);
      }
      ...
      myFunction() {
        this.context.router.history.push("/some/Path");
      }
      ...
    }

    ดูเอกสารอย่างเป็นทางการเกี่ยวกับบริบท:

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

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


9
ใช่ฉันลองแล้ว ขอบคุณที่ถาม. :-) ดังนั้นคุณจะรับบริบทในฟังก์ชั่นการกระทำนี้ได้อย่างไร? จนถึงตอนนี้มันก็มาถึงไม่ได้กำหนด
Chris

1
ฉันค้นคว้าหัวข้อนี้มาหลายวันแล้วและไม่สามารถใช้งานได้ แม้แต่การใช้ตัวอย่างด้านบนฉันยังได้รับเราเตอร์ไม่ได้กำหนดในบริบท ฉันกำลังใช้ react v15.5.10, react-router-dom v4.1.1, prop-types 15.5.10 เอกสารเกี่ยวกับเรื่องนี้กระจัดกระจายและไม่ค่อยชัดเจน
Stu

5
@Stu นี้ใช้งานได้this.context.router.history.push('/path');
Tushar Khatiwada

1
@Chris แน่นอนถ้าคุณพยายามที่จะยกตัวอย่างวัตถุประวัติศาสตร์และใช้ด้วยตัวเองมันจะเปลี่ยน URL แต่จะไม่แสดงองค์ประกอบ - ตามที่คุณกล่าวข้างต้น แต่วิธีการใช้ "history.push" ด้านนอกขององค์ประกอบและองค์ประกอบบังคับให้แสดงเช่นกัน?
เย็น

52
นี่ไม่ได้ตอบคำถามที่ถูกถามซึ่งเป็นวิธีการเข้าถึงประวัติกดด้านนอกของส่วนประกอบ การใช้ withRouter หรือบริบทไม่ใช่ตัวเลือกสำหรับเมื่ออยู่นอกองค์ประกอบ
SunshinyDoyle

49

ขณะนี้มี react-router v5 คุณสามารถใช้ฮุควงจรชีวิตการใช้งานเช่นนี้:

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

function HomeButton() {
  let history = useHistory();

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

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

อ่านเพิ่มเติมได้ที่: https://reacttraining.com/react-router/web/api/Hooks/usehistory


1
เป็นการอัปเดตที่น่ายินดีมาก! ขอบคุณ!
Chris

มีวิธีใดที่ฉันต้องตั้งค่านี้ฉันกำลังเรียกสิ่งต่อไปนี้let history = useHistory();แต่ได้รับObject is not callableข้อผิดพลาดเมื่อฉันลองดูว่าการใช้งานประวัติใดconsole.log(useHistory)ปรากฏขึ้นในลักษณะที่ไม่ได้กำหนด ใช้"react-router-dom": "^5.0.1"
steff_bdh

@steff_bdh คุณต้องอัปเดตในไฟล์ yout package.json เป็น "react-router-dom": "^ 5.0.1" และเรียกใช้ 'npm install'
Hadi Abu

2
ดี แต่ไม่สามารถใช้เบ็ดภายในคลาสแอคชั่น redux เนื่องจากพวกเขาไม่ใช่ React component / function
Jay

คุณจะใช้สิ่งนี้เพื่อเปลี่ยนเส้นทางอย่างไรเมื่อเข้าสู่ระบบโดยใช้ (async) นี่คือคำถาม => stackoverflow.com/questions/62154408/…
theairbend3r

29

วิธีที่ง่ายที่สุดใน React Router 4 คือการใช้

this.props.history.push('/new/url');

แต่การใช้วิธีนี้ส่วนประกอบที่มีอยู่ของคุณควรมีสิทธิ์เข้าถึงhistoryวัตถุ เราสามารถเข้าถึงได้โดย

  1. หากส่วนประกอบของคุณเชื่อมโยงRouteโดยตรงส่วนประกอบของคุณจะสามารถเข้าถึงhistoryวัตถุได้แล้ว

    เช่น:

    <Route path="/profile" component={ViewProfile}/>

    ที่นี่มีการเข้าถึงViewProfilehistory

  2. หากไม่ได้เชื่อมต่อRouteโดยตรง

    เช่น:

    <Route path="/users" render={() => <ViewUsers/>}

    จากนั้นเราต้องใช้withRouterคำสั่งที่สูงขึ้นเพื่อบิดเบือนองค์ประกอบที่มีอยู่

    ViewUsersส่วนประกอบภายใน

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

    • export default withRouter(ViewUsers);

    นั่นคือตอนนี้ViewUsersองค์ประกอบของคุณมีการเข้าถึงhistoryวัตถุ

UPDATE

2- ในสถานการณ์นี้ส่งเส้นทางทั้งหมดpropsไปยังส่วนประกอบของคุณแล้วเราสามารถเข้าถึงได้this.props.historyจากส่วนประกอบแม้ไม่มีHOC

เช่น:

<Route path="/users" render={props => <ViewUsers {...props} />}

1
ยอดเยี่ยม วิธีที่สองของคุณได้ทำเคล็ดลับสำหรับฉันด้วยเนื่องจากองค์ประกอบของฉัน (ซึ่งต้องการการเข้าถึงthis.props.history) มาจาก HOC ซึ่งหมายความว่ามันไม่ได้เชื่อมโยงโดยตรงกับวิธีRouteดังที่คุณอธิบาย
cjauvin

25

นี่คือวิธีที่ฉันทำ:

import React, {Component} from 'react';

export default class Link extends Component {
    constructor(props) {
        super(props);
        this.onLogout = this.onLogout.bind(this);
    }
    onLogout() {
        this.props.history.push('/');
    }
    render() {
        return (
            <div>
                <h1>Your Links</h1>
                <button onClick={this.onLogout}>Logout</button>
            </div>
        );
    }
}

ใช้this.props.history.push('/cart');เพื่อเปลี่ยนเส้นทางไปยังหน้ารถเข็นมันจะถูกบันทึกไว้ในวัตถุประวัติ

สนุกไมเคิล


2
ใช่ดูเหมือนว่าภายในองค์ประกอบที่คุณสามารถผลักดันได้ดี วิธีเดียวที่จะส่งผลกระทบต่อการนำทางนอกองค์ประกอบคือการเปลี่ยนเส้นทาง
Chris

14
นี่ไม่ได้ตอบคำถามที่ถูกถามซึ่งเป็นวิธีการเข้าถึงประวัติกดด้านนอกของส่วนประกอบ ใช้ this.props.history ไม่ใช่ตัวเลือกสำหรับเมื่ออยู่นอกส่วนประกอบ
SunshinyDoyle

22

ตามเอกสาร React Router v4 - เซสชัน Redux Deep Integration

จำเป็นต้องมีการรวมเข้าด้วยกันเพื่อ:

"สามารถนำทางด้วยการส่งการกระทำ"

อย่างไรก็ตามพวกเขาแนะนำวิธีการนี้เป็นทางเลือกแทน "การผสานรวมที่ลึก":

"แทนที่จะส่งการกระทำเพื่อนำทางคุณสามารถส่งประวัติวัตถุที่ให้ไว้เพื่อกำหนดเส้นทางส่วนประกอบไปยังการกระทำของคุณและนำทางไปที่นั่น"

ดังนั้นคุณสามารถห่อส่วนประกอบของคุณด้วยส่วนประกอบลำดับสูงได้:

export default withRouter(connect(null, { actionCreatorName })(ReactComponent));

ซึ่งจะส่งประวัติ API ไปยังอุปกรณ์ประกอบฉาก ดังนั้นคุณสามารถเรียกผู้สร้างแอคชั่นที่ผ่านประวัติศาสตร์เป็นพารามิเตอร์ได้ ตัวอย่างเช่นภายใน ReactComponent ของคุณ:

onClick={() => {
  this.props.actionCreatorName(
    this.props.history,
    otherParams
  );
}}

จากนั้นภายในการกระทำของคุณ / index.js:

export function actionCreatorName(history, param) {
  return dispatch => {
    dispatch({
      type: SOME_ACTION,
      payload: param.data
    });
    history.push("/path");
  };
}

19

คำถามที่น่ารังเกียจทำให้ฉันมีเวลาค่อนข้างมาก แต่ในที่สุดฉันก็แก้ไขด้วยวิธีนี้:

ห่อภาชนะของคุณด้วยwithRouterและส่งประวัติไปที่แอ็ค mapDispatchToPropsชั่นของคุณ ในการดำเนินการใช้ history.push ('/ url') เพื่อนำทาง

หนังบู๊:

export function saveData(history, data) {
  fetch.post('/save', data)
     .then((response) => {
       ...
       history.push('/url');
     })
};

คอนเทนเนอร์:

import { withRouter } from 'react-router-dom';
...
const mapDispatchToProps = (dispatch, ownProps) => {
  return {
    save: (data) => dispatch(saveData(ownProps.history, data))}
};
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Container));

นี้สามารถใช้ได้สำหรับการตอบสนอง Router v4.x


ขอบคุณโซลูชัน withRouter ของคุณทำงานกับ typescript แต่ค่อนข้างช้าเมื่อเทียบกับimport { createBrowserHistory } from 'history' ความคิดก่อนหน้านี้โปรด?
Jay

7

this.context.history.push จะไม่ทำงาน.

ฉันพยายามที่จะผลักดันการทำงานเช่นนี้:

static contextTypes = {
    router: PropTypes.object
}

handleSubmit(e) {
    e.preventDefault();

    if (this.props.auth.success) {
        this.context.router.history.push("/some/Path")
    }

}

9
นี่ไม่ได้ตอบคำถามที่ถูกถามซึ่งเป็นวิธีการเข้าถึงประวัติกดด้านนอกของส่วนประกอบ ใช้ this.context ไม่ใช่ตัวเลือกสำหรับเมื่ออยู่นอกองค์ประกอบ
SunshinyDoyle

6

ในกรณีนี้คุณกำลังส่งอุปกรณ์ประกอบฉากไปที่อันธพาลของคุณ ดังนั้นคุณสามารถโทร

props.history.push('/cart')

หากไม่ใช่กรณีนี้คุณยังสามารถส่งประวัติจากส่วนประกอบของคุณได้

export function addProduct(data, history) {
  return dispatch => {
    axios.post('/url', data).then((response) => {
      dispatch({ type: types.AUTH_USER })
      history.push('/cart')
    })
  }
}

6

ฉันขอเสนอวิธีแก้ปัญหาเพิ่มเติมอีกหนึ่งกรณีในกรณีที่มีประโยชน์ต่อผู้อื่น

ฉันมีhistory.jsไฟล์ที่ฉันมีดังต่อไปนี้:

import createHistory from 'history/createBrowserHistory'
const history = createHistory()
history.pushLater = (...args) => setImmediate(() => history.push(...args))
export default history

ต่อไปบนรูทของฉันที่ฉันกำหนดเราเตอร์ของฉันฉันใช้ต่อไปนี้:

import history from '../history'
import { Provider } from 'react-redux'
import { Router, Route, Switch } from 'react-router-dom'

export default class Root extends React.Component {
  render() {
    return (
     <Provider store={store}>
      <Router history={history}>
       <Switch>
        ...
       </Switch>
      </Router>
     </Provider>
    )
   }
  }

ในที่สุดฉันactions.jsก็นำเข้าประวัติและใช้ประโยชน์จาก pushLater

import history from './history'
export const login = createAction(
...
history.pushLater({ pathname: PATH_REDIRECT_LOGIN })
...)

ด้วยวิธีนี้ฉันสามารถผลักดันให้ดำเนินการใหม่หลังจากเรียก API

หวังว่ามันจะช่วย!


4

หากคุณกำลังใช้ Redux แล้วฉันจะแนะนำให้ใช้แพคเกจ NPM ตอบสนองเตอร์-Redux ช่วยให้คุณสามารถจัดส่งการกระทำการนำทางในร้านค้าของ Redux

คุณต้องสร้างร้านค้าที่อธิบายไว้ในของพวกเขาให้ไฟล์ Readme

กรณีการใช้งานที่ง่ายที่สุด:

import { push } from 'react-router-redux'

this.props.dispatch(push('/second page'));

กรณีการใช้งานครั้งที่สองพร้อมคอนเทนเนอร์ / ส่วนประกอบ:

คอนเทนเนอร์:

import { connect } from 'react-redux';
import { push } from 'react-router-redux';

import Form from '../components/Form';

const mapDispatchToProps = dispatch => ({
  changeUrl: url => dispatch(push(url)),
});

export default connect(null, mapDispatchToProps)(Form);

ส่วนประกอบคือ:

import React, { Component } from 'react';
import PropTypes from 'prop-types';

export default class Form extends Component {
  handleClick = () => {
    this.props.changeUrl('/secondPage');
  };

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

1
ใช้งานไม่ได้กับ react-router-redux เว้นแต่คุณจะใช้nextเวอร์ชั่นซึ่งยังอยู่ระหว่างการพัฒนาในขณะนี้!
froginvasion

4

bind()ผมสามารถที่จะบรรลุนี้โดยใช้ ผมอยากจะคลิกที่ปุ่มในโพสต์ข้อมูลบางส่วนไปยังเซิร์ฟเวอร์ประเมินผลการตอบสนองและเปลี่ยนเส้นทางไปยังindex.jsx success.jsxนี่คือวิธีที่ฉันทำงานออก ...

index.jsx:

import React, { Component } from "react"
import { postData } from "../../scripts/request"

class Main extends Component {
    constructor(props) {
        super(props)
        this.handleClick = this.handleClick.bind(this)
        this.postData = postData.bind(this)
    }

    handleClick() {
        const data = {
            "first_name": "Test",
            "last_name": "Guy",
            "email": "test@test.com"
        }

        this.postData("person", data)
    }

    render() {
        return (
            <div className="Main">
                <button onClick={this.handleClick}>Test Post</button>
            </div>
        )
    }
}

export default Main

request.js:

import { post } from "./fetch"

export const postData = function(url, data) {
    // post is a fetch() in another script...
    post(url, data)
        .then((result) => {
            if (result.status === "ok") {
                this.props.history.push("/success")
            }
        })
}

success.jsx:

import React from "react"

const Success = () => {
    return (
        <div className="Success">
            Hey cool, got it.
        </div>
    )
}

export default Success

ดังนั้นโดยมีผลผูกพันthisไปpostDataในindex.jsxผมก็สามารถที่จะเข้าถึงthis.props.historyในrequest.js... แล้วฉันสามารถใช้ฟังก์ชั่นนี้ในส่วนที่แตกต่างกันเพียงแค่ต้องทำให้แน่ใจว่าผมจำได้ว่าจะรวมอยู่ในthis.postData = postData.bind(this)constructor()


3

นี่คือแฮ็คของฉัน (นี่คือไฟล์ระดับรากของฉันโดยมี redux เล็กน้อยผสมอยู่ในนั้น - แม้ว่าฉันไม่ได้ใช้react-router-redux):

const store = configureStore()
const customHistory = createBrowserHistory({
  basename: config.urlBasename || ''
})

ReactDOM.render(
  <Provider store={store}>
    <Router history={customHistory}>
      <Route component={({history}) => {
        window.appHistory = history
        return (
          <App />
        )
      }}/>
    </Router>
  </Provider>,
  document.getElementById('root')
)

ฉันสามารถใช้งานwindow.appHistory.push()ได้ทุกที่ที่ต้องการ (ตัวอย่างเช่นในฟังก์ชั่นการจัดเก็บของ redux / thunks / sagas ฯลฯ ) ฉันหวังว่าฉันจะสามารถใช้งานได้window.customHistory.push()แต่ด้วยเหตุผลบางอย่างreact-routerดูเหมือนจะไม่อัปเดตแม้ว่า url จะเปลี่ยนไป แต่วิธีนี้ฉันreact-routerใช้อินสแตนซ์ที่แน่นอน ฉันไม่ชอบที่จะวางสิ่งของในขอบเขตทั่วโลกและนี่คือหนึ่งในสองสามสิ่งที่ฉันทำ แต่มันดีกว่าทางเลือกอื่นที่ฉันเคยเห็น IMO


3

ใช้โทรกลับ มันใช้งานได้สำหรับฉัน!

export function addProduct(props, callback) {
  return dispatch =>
    axios.post(`${ROOT_URL}/cart`, props, config)
    .then(response => {
    dispatch({ type: types.AUTH_USER });
    localStorage.setItem('token', response.data.token);
    callback();
  });
}

ในองค์ประกอบคุณเพียงแค่ต้องเพิ่มการโทรกลับ

this.props.addProduct(props, () => this.props.history.push('/cart'))

3

ดังนั้นวิธีที่ฉันทำคือ: - แทนที่จะเปลี่ยนเส้นทางโดยใช้history.pushฉันแค่ใช้Redirectส่วนประกอบจากreact-router-dom เมื่อใช้ส่วนนี้คุณก็สามารถผ่านpush=trueและมันจะดูแลส่วนที่เหลือ

import * as React from 'react';
import { Redirect } from 'react-router-dom';
class Example extends React.Component {
  componentDidMount() {
    this.setState({
      redirectTo: '/test/path'
    });
  }

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

    return <Redirect to={{pathname: redirectTo}} push={true}/>
  }
}

นี่คือสิ่งที่ถูกต้องซึ่งไม่ทำให้วงจรการแสดงภาพซ้ำ
jzqa

1

React router V4 ตอนนี้อนุญาตให้ใช้ prop ประวัติได้ดังนี้:

this.props.history.push("/dummy",value)

จากนั้นสามารถเข้าถึงค่าได้ทุกที่ที่ตั้ง prop พร้อมใช้งานใน state:{value}สถานะไม่ใช่ส่วนประกอบ


1
นี่ไม่ได้ตอบคำถามที่ถูกถามซึ่งเป็นวิธีการเข้าถึงประวัติกดด้านนอกของส่วนประกอบ ใช้ this.props.history ไม่ใช่ตัวเลือกสำหรับเมื่ออยู่นอกส่วนประกอบ
Arkady

0

คุณสามารถใช้มันแบบนี้เพราะฉันทำเพื่อล็อกอินและแมนนี่ต่าง ๆ

class Login extends Component {
  constructor(props){
    super(props);
    this.login=this.login.bind(this)
  }


  login(){
this.props.history.push('/dashboard');
  }


render() {

    return (

   <div>
    <button onClick={this.login}>login</login>
    </div>

)

0
/*Step 1*/
myFunction(){  this.props.history.push("/home"); }
/**/
 <button onClick={()=>this.myFunction()} className={'btn btn-primary'}>Go 
 Home</button>

ไม่จำเป็นต้องมีการนำเข้าใด ๆ !
David Bagdasaryan

1
ในขณะที่รหัสนี้อาจตอบคำถาม แต่มีบริบทเพิ่มเติมเกี่ยวกับสาเหตุและ / หรือวิธีการที่รหัสนี้ตอบคำถามช่วยปรับปรุงมูลค่าระยะยาว
rollstuhlfahrer

0

ขั้นตอนที่หนึ่งห่อแอปของคุณในเราเตอร์

import { BrowserRouter as Router } from "react-router-dom";
ReactDOM.render(<Router><App /></Router>, document.getElementById('root'));

ตอนนี้แอพทั้งหมดของฉันจะสามารถเข้าถึง BrowserRouter ขั้นตอนที่สองฉันนำเข้าเส้นทางแล้วส่งผ่านอุปกรณ์ประกอบฉากเหล่านั้น อาจเป็นหนึ่งในไฟล์หลักของคุณ

import { Route } from "react-router-dom";

//lots of code here

//somewhere in my render function

    <Route
      exact
      path="/" //put what your file path is here
      render={props => (
      <div>
        <NameOfComponent
          {...props} //this will pass down your match, history, location objects
        />
      </div>
      )}
    />

ตอนนี้ถ้าฉันเรียกใช้ console.log (this.props) ในไฟล์คอมโพเนนต์ js ของฉันที่ฉันควรได้รับสิ่งที่มีลักษณะเช่นนี้

{match: {…}, location: {…}, history: {…}, //other stuff }

ขั้นตอนที่ 2 ฉันสามารถเข้าถึงวัตถุประวัติเพื่อเปลี่ยนตำแหน่งของฉัน

//lots of code here relating to my whatever request I just ran delete, put so on

this.props.history.push("/") // then put in whatever url you want to go to

นอกจากนี้ฉันเป็นนักเรียน bootcamp ที่เข้ารหัสดังนั้นฉันจึงไม่มีความเชี่ยวชาญ แต่ฉันรู้ว่าคุณสามารถใช้

window.location = "/" //wherever you want to go

แก้ไขให้ถูกต้องถ้าฉันผิด แต่เมื่อฉันทดสอบออกมามันจะโหลดหน้าทั้งหมดซึ่งฉันคิดว่าแพ้จุดที่ใช้ React ไปทั้งหมด


0

สร้างกำหนดเองRouterด้วยตนเองbrowserHistory:

import React from 'react';
import { Router } from 'react-router-dom';
import { createBrowserHistory } from 'history';

export const history = createBrowserHistory();

const ExtBrowserRouter = ({children}) => (
  <Router history={history} >
  { children }
  </Router>
);

export default ExtBrowserRouter

ถัดไปบนรูทของคุณซึ่งคุณกำหนดRouterให้ใช้สิ่งต่อไปนี้:

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

//Use 'ExtBrowserRouter' instead of 'BrowserRouter'
import ExtBrowserRouter from './ExtBrowserRouter'; 
...

export default class Root extends React.Component {
  render() {
    return (
      <Provider store={store}>
        <ExtBrowserRouter>
          <Switch>
            ...
            <Route path="/login" component={Login}  />
            ...
          </Switch>
        </ExtBrowserRouter>
      </Provider>
    )
  }
}

สุดท้ายนำเข้าhistoryที่ที่คุณต้องการและใช้งาน:

import { history } from '../routers/ExtBrowserRouter';
...

export function logout(){
  clearTokens();      
  history.push('/login'); //WORKS AS EXPECTED!
  return Promise.reject('Refresh token has expired');
}

0

หากคุณต้องการใช้ประวัติในขณะที่ส่งผ่านฟังก์ชั่นเป็นค่าไปยัง prop ของ Component ด้วยreact-router 4คุณสามารถทำลายhistoryprop ในแอตทริบิวต์ render ของ<Route/>Component จากนั้นใช้history.push()

    <Route path='/create' render={({history}) => (
      <YourComponent
        YourProp={() => {
          this.YourClassMethod()
          history.push('/')
        }}>
      </YourComponent>
    )} />

หมายเหตุ: เพื่อให้สิ่งนี้ใช้งานได้คุณควรห่อส่วนประกอบ BrowserRouter ของ React Router ไว้รอบ ๆ องค์ประกอบรากของคุณ (เช่น. ซึ่งอาจอยู่ใน index.js)

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