จะรับประวัติบน react-router v4 ได้อย่างไร


106

ฉันมีปัญหาเล็กน้อยในการย้ายจาก React-Router v3 ไปเป็น v4 ใน v3 ฉันสามารถทำได้ทุกที่:

import { browserHistory } from 'react-router';
browserHistory.push('/some/path');

ฉันจะบรรลุสิ่งนี้ใน v4.1 ได้อย่างไร

ฉันรู้ว่าฉันสามารถใช้, hoc withRouter, react context หรือ event router props เมื่อคุณอยู่ใน Component แต่มันไม่ใช่กรณีสำหรับฉัน

ฉันกำลังมองหาความเทียบเท่าของNavigatingOutsideOfComponentsใน v4


1
ขอบคุณ @Chris แต่อย่างที่บอกว่าฉันไม่ได้อยู่ใน Component
storm_buster

@Chris ในคลาสยูทิลิตี้โปรดตรวจสอบgithub.com/ReactTraining/react-router/blob/master/docs/guides/…อาจเป็นตัวกลาง
สำรอง

วิธีที่ง่ายที่สุดstackoverflow.com/a/53916596/3966458
Saahithyan Vigneswaran

ฉันลงเอยด้วยการใช้ BrowserRouter เป็นส่วนประกอบหลัก ด้วยวิธีนี้ฉันสามารถใช้ส่วนประกอบแอพกับเราเตอร์ ไม่ตรงกับสิ่งที่คุณขอ แต่ฉันมีข้อกำหนดเดียวกันนี้ก็เพียงพอแล้วสำหรับฉัน
The Fool

คำตอบ:


184

คุณต้องมีโมดูลที่ส่งออกhistoryวัตถุ จากนั้นคุณจะนำเข้าวัตถุนั้นตลอดทั้งโครงการของคุณ

// history.js
import { createBrowserHistory } from 'history'

export default createBrowserHistory({
  /* pass a configuration object here if needed */
})

จากนั้นแทนที่จะใช้เราเตอร์ในตัวคุณจะใช้<Router>คอมโพเนนต์

// index.js
import { Router } from 'react-router-dom'
import history from './history'
import App from './App'

ReactDOM.render((
  <Router history={history}>
    <App />
  </Router>
), holder)
// some-other-file.js
import history from './history'
history.push('/go-here')

1
ขอบคุณมาก! ในขณะนี้โดยใช้ react-router4 ฉันต้องใช้การนำเข้านี้ใน history.js แทน: import createBrowserHistory จาก 'history / createBrowserHistory';
peter.bartos

3
มันใช้ได้ผลสำหรับฉันเมื่อฉันใส่ history = {history} ในเส้นทางและผ่านไปเหมือนอุปกรณ์ประกอบฉาก
Nath Paiva

1
เราสามารถใช้ withHistory และรับประวัติในอุปกรณ์ประกอบฉากแทนที่จะสร้างไฟล์แยกต่างหาก วิธีนี้ใช้ไม่ได้กับฉันกับ redux
Zeel Shah

4
นำเข้าถ้าคุณใช้createHashHistory HashRouter
David Harkness

2
@HassanAzzam คุณอาจใช้ react-router V5 และคำตอบนี้ใช้ได้กับ V4 ไม่ใช่ V5 ตอนนี้ฉันมีความท้าทายเดียวกันและกำลังมองหาทุกที่ แต่ไม่สามารถทำให้มันได้ผล history.push ภายนอกคอมโพเนนต์ใช้งานได้ แต่คลิกลิงก์ไม่ได้อีกต่อไป
Waterlink

73

ได้ผล! https://reacttraining.com/react-router/web/api/withRouter

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

class MyComponent extends React.Component {
  render () {
    this.props.history;
  }
}

withRouter(MyComponent);

27
ตราบเท่าที่คุณอยู่ในส่วนประกอบ ฉันไม่ได้อยู่ในส่วนประกอบ
storm_buster

1
ขอบคุณนี่เป็นวิธีที่ง่ายและตรงไปตรงมาที่สุดในการเชื่อมโยงไปยังเส้นทางอื่นจากส่วนประกอบ ฉันจะเพิ่มว่าคุณต้องทำthis.props.history.push('/some_route');เพื่อให้มันใช้งานได้
dannytenaglias

1
@storm_buster const Component = props => {... // stuff}และexport default withRouter(Component)ทำงานให้ฉันในองค์ประกอบที่ไร้สัญชาติ
Karl Taylor

11

คำตอบที่ยอมรับได้ในสิ่งที่คุณทำได้คือใช้reactและreact-routerตัวมันเองเพื่อให้คุณhistoryคัดค้านซึ่งคุณสามารถกำหนดขอบเขตในไฟล์แล้วส่งออก

history.js

import React from 'react';
import { withRouter } from 'react-router';

// variable which will point to react-router history
let globalHistory = null;

// component which we will mount on top of the app
class Spy extends React.Component {
  constructor(props) {
    super(props)
    globalHistory = props.history; 
  }

  componentDidUpdate() {
    globalHistory = this.props.history;
  }

  render(){
    return null;
  }
}

export const GlobalHistory = withRouter(Spy);

// export react-router history
export default function getHistory() {    
  return globalHistory;
}

จากนั้นนำเข้าคอมโพเนนต์และต่อเชื่อมเพื่อเริ่มต้นตัวแปรประวัติ:

import { BrowserRouter } from 'react-router-dom';
import { GlobalHistory } from './history';

function render() {
  ReactDOM.render(
    <BrowserRouter>
        <div>
            <GlobalHistory />
            //.....
        </div>
    </BrowserRouter>
    document.getElementById('app'),
  );
}

จากนั้นคุณสามารถนำเข้าในแอปของคุณได้เมื่อติดตั้งแล้ว:

import getHistory from './history'; 

export const goToPage = () => (dispatch) => {
  dispatch({ type: GO_TO_SUCCESS_PAGE });
  getHistory().push('/success'); // at this point component probably has been mounted and we can safely get `history`
};

ฉันยังทำและแพ็คเกจ npmที่ทำแบบนั้น


สำหรับ reactjs 16.9 โซลูชันนี้จะพ่นคำเตือนการเลิกใช้งานบน componentWillMount และ componentWillReceiveProps
ian

1
@ian true แก้ไขว่า
Tomasz Mularczyk

5

หากคุณใช้ redux และ redux-thunk ทางออกที่ดีที่สุดคือใช้react-router-redux

// then, in redux actions for example
import { push } from 'react-router-redux'

dispatch(push('/some/path'))

สิ่งสำคัญคือต้องดูเอกสารเพื่อทำการกำหนดค่าบางอย่าง


1
ฉันมาที่นี่โดยหวังว่าจะพบวิธีแก้ปัญหาที่แน่นอนนี้ขอบคุณ
vapurrmaid

5

ขึ้นอยู่กับคำตอบนี้หากคุณต้องการวัตถุประวัติเท่านั้นเพื่อนำทางไปยังส่วนประกอบอื่น ๆ :

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

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

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

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

ผิดคุณอยู่ในองค์ประกอบ ดู // some-other-file.js จากคำตอบที่ยอมรับ
storm_buster

0

ใน App.js

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

 const TheContext = React.createContext(null);

 const App = () => {
   const history = useHistory();

   <TheContext.Provider value={{ history, user }}>

    <Switch>
        <Route exact path="/" render={(props) => <Home {...props} />} />
        <Route
          exact
          path="/sign-up"
          render={(props) => <SignUp {...props} setUser={setUser} />}
        /> ...

จากนั้นในองค์ประกอบลูก:

const Welcome = () => {
    
    const {user, history} = React.useContext(TheContext); 
    ....

-2

ในกรณีเฉพาะของการreact-routerใช้contextเป็นสถานการณ์กรณีที่ถูกต้องเช่น

class MyComponent extends React.Component {
  props: PropsType;

  static contextTypes = {
    router: PropTypes.object
  };

  render () {
    this.context.router;
  }
}

this.context.router.historyคุณสามารถเข้าถึงอินสแตนซ์ของประวัติศาสตร์ผ่านบริบทเราเตอร์เช่น


คำถามเฉพาะถามเกี่ยวกับเมื่ออยู่นอกคอมโพเนนต์ดังนั้น this.context จึงไม่พร้อมใช้งานเป็นตัวเลือก:> "ฉันรู้ว่าฉันสามารถใช้ hoc withRouter บริบทตอบสนองหรืออุปกรณ์ประกอบฉากเราเตอร์เมื่อคุณอยู่ในคอมโพเนนต์ แต่ มันไม่ใช่กรณีสำหรับฉัน "
SunshinyDoyle
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.