Điều hướng lập trình bằng cách sử dụng bộ định tuyến phản ứng V4


335

Tôi vừa thay thế react-routertừ v3 sang v4.
Nhưng tôi không chắc chắn làm thế nào để điều hướng theo chương trình trong chức năng thành viên của a Component. tức là trong handleClick()chức năng tôi muốn điều hướng đến /path/some/wheresau khi xử lý một số dữ liệu. Tôi đã từng làm điều đó bằng cách:

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

Nhưng tôi không thể tìm thấy các giao diện như vậy trong v4.
Làm cách nào tôi có thể điều hướng bằng v4?


3
Bạn có thể truy cập đối tượng lịch sử trong v4 thông qua các đạo cụ: this.props.history.push ('/')
colemerrick

6
Điều gì nếu bạn muốn truy cập nó từ một nơi khác ngoài một Component? Ví dụ, bên trong các hành động redux.
Maximus S

73
đôi khi tôi tự hỏi tại sao nó lại phức tạp đến mức chỉ chuyển từ liên kết này sang liên kết khác =))
Thái Trần

12
Mọi người sẽ nghĩ rằng trong thời đại ngày nay, việc chuyển hướng sẽ không quá phức tạp.
John ALLen

Tôi thấy bài đăng này hữu ích: Medium.com/@anneeb/redirecting-in-react-4de5e517354a
BioData41

Câu trả lời:


413

Nếu bạn đang nhắm mục tiêu môi trường trình duyệt, bạn cần sử dụng react-router-dom gói, thay vì react-router. Họ đang theo cách tiếp cận giống như React đã làm, để tách lõi, ( react) và mã cụ thể của nền tảng, ( react-dom, react-native) với sự khác biệt tinh tế mà bạn không cần phải cài đặt hai gói riêng biệt, vì vậy các gói môi trường chứa mọi thứ bạn cần. Bạn có thể thêm nó vào dự án của bạn như:

yarn add react-router-dom

hoặc là

npm i react-router-dom

Điều đầu tiên bạn cần làm là cung cấp một <BrowserRouter>thành phần cha mẹ hàng đầu trong ứng dụng của bạn. <BrowserRouter>sử dụng historyAPI HTML5 và quản lý nó cho bạn, vì vậy bạn không phải lo lắng về việc tự khởi tạo nó và chuyển nó xuống <BrowserRouter>thành phần dưới dạng chống đỡ (như bạn cần làm trong các phiên bản trước).

Trong V4, để điều hướng theo chương trình, bạn cần truy cập vào historyđối tượng, có sẵn thông qua React context, miễn là bạn có một thành phần <BrowserRouter> nhà cung cấp là phụ huynh hàng đầu trong ứng dụng của bạn. Thư viện phơi bày thông qua bối cảnh routerđối tượng, mà chính nó chứa historynhư một tài sản. Các historygiao diện cung cấp một số phương pháp định vị, chẳng hạn như push, replacegoBack , trong số những người khác. Bạn có thể kiểm tra toàn bộ danh sách các thuộc tính và phương thức ở đây .

Lưu ý quan trọng đối với người dùng Redux / Mobx

Nếu bạn đang sử dụng redux hoặc mobx làm thư viện quản lý trạng thái trong ứng dụng của mình, bạn có thể gặp phải các vấn đề với các thành phần cần nhận biết vị trí nhưng không được hiển thị lại sau khi kích hoạt cập nhật URL

Điều đó xảy ra bởi vì react-router chuyển locationđến các thành phần sử dụng mô hình bối cảnh.

Cả kết nối và người quan sát đều tạo ra các thành phần mà các phương thức ShouldComponentUpdate thực hiện so sánh nông cạn về các đạo cụ hiện tại và các đạo cụ tiếp theo của chúng. Những thành phần đó sẽ chỉ kết xuất lại khi có ít nhất một chỗ dựa đã thay đổi. Điều này có nghĩa là để đảm bảo họ cập nhật khi vị trí thay đổi, họ sẽ cần được cung cấp một chỗ dựa thay đổi khi vị trí thay đổi.

Hai cách tiếp cận để giải quyết điều này là:

  • Bọc thành phần được kết nối của bạn một cách vô lối<Route /> . locationĐối tượng hiện tại là một trong những đạo cụ <Route>truyền cho thành phần mà nó hiển thị
  • Bọc thành phần được kết nối của bạn vớiwithRouter bậc cao hơn, trên thực tế có tác dụng tương tự và tiêm locationnhư một chỗ dựa

Đặt điều đó sang một bên, có bốn cách để điều hướng theo chương trình, được sắp xếp theo khuyến nghị:

1.- Sử dụng một <Route> thành phần

Nó thúc đẩy một phong cách khai báo. Trước v4, <Route />các thành phần được đặt ở đầu phân cấp thành phần của bạn, trước tiên phải nghĩ đến cấu trúc tuyến đường của bạn. Tuy nhiên, bây giờ bạn có thể có <Route>các thành phần ở bất kỳ đâu trong cây của mình, cho phép bạn có quyền kiểm soát tốt hơn để hiển thị có điều kiện tùy thuộc vào URL. Routetiêm match, locationhistorynhư là đạo cụ vào thành phần của bạn. Các phương pháp định vị (ví dụ như push, replace,goBack ...) có sẵn như là thuộc tính của historyđối tượng.

Có 3 cách để làm cho một cái gì đó với một Route, bằng cách sử dụng một trong hai component, renderhoặc childrenđạo cụ, nhưng không sử dụng nhiều hơn một trong cùng Route. Lựa chọn tùy thuộc vào trường hợp sử dụng, nhưng về cơ bản, hai tùy chọn đầu tiên sẽ chỉ hiển thị thành phần của bạn nếu pathkhớp với vị trí url, trong khi đó với childrenthành phần sẽ được hiển thị xem đường dẫn có khớp với vị trí đó hay không (hữu ích cho việc điều chỉnh UI dựa trên URL phù hợp).

Nếu bạn muốn tùy chỉnh đầu ra vẽ thành phần của bạn , bạn cần phải quấn thành phần của bạn trong một chức năng và sử dụng các rendertùy chọn, để vượt qua thành phần của bạn bất kỳ đạo cụ khác mà bạn mong muốn, ngoài match, locationhistory. Một ví dụ để minh họa:

import { BrowserRouter as Router } from 'react-router-dom'

const ButtonToNavigate = ({ title, history }) => (
  <button
    type="button"
    onClick={() => history.push('/my-new-location')}
  >
    {title}
  </button>
);

const SomeComponent = () => (
  <Route path="/" render={(props) => <ButtonToNavigate {...props} title="Navigate elsewhere" />} />
)    

const App = () => (
  <Router>
    <SomeComponent /> // Notice how in v4 we can have any other component interleaved
    <AnotherComponent />
  </Router>
);

2.- Sử dụng withRouterHoC

Thành phần bậc cao này sẽ tiêm các đạo cụ tương tự như Route. Tuy nhiên, nó mang theo giới hạn rằng bạn chỉ có thể có 1 HoC cho mỗi tệp.

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

const ButtonToNavigate = ({ history }) => (
  <button
    type="button"
    onClick={() => history.push('/my-new-location')}
  >
    Navigate
  </button>
);


ButtonToNavigate.propTypes = {
  history: React.PropTypes.shape({
    push: React.PropTypes.func.isRequired,
  }),
};

export default withRouter(ButtonToNavigate);

3.- Sử dụng một Redirectthành phần

Kết xuất <Redirect>sẽ điều hướng đến một vị trí mới. Nhưng hãy nhớ rằng, theo mặc định , vị trí hiện tại được thay thế bằng vị trí mới, như chuyển hướng phía máy chủ (HTTP 3xx). Vị trí mới được cung cấp bởi toprop, có thể là một chuỗi (URL để chuyển hướng đến) hoặc một locationđối tượng. Thay vào đó, nếu bạn muốn đẩy một mục mới vào lịch sử , hãy chuyển một chỗ dựa pushvà đặt nó thànhtrue

<Redirect to="/your-new-location" push />

4.- Truy cập routerthủ công thông qua ngữ cảnh

Một chút nản lòng vì bối cảnh vẫn là một API thử nghiệm và nó có khả năng phá vỡ / thay đổi trong các bản phát hành React trong tương lai

const ButtonToNavigate = (props, context) => (
  <button
    type="button"
    onClick={() => context.router.history.push('/my-new-location')}
  >
    Navigate to a new location
  </button>
);

ButtonToNavigate.contextTypes = {
  router: React.PropTypes.shape({
    history: React.PropTypes.object.isRequired,
  }),
};

Không cần phải nói, cũng có các thành phần Bộ định tuyến khác dành cho các hệ sinh thái không có trình duyệt, chẳng hạn như <NativeRouter>sao chép ngăn xếp điều hướng trong bộ nhớ và nhắm mục tiêu nền tảng React Native, có sẵn thông qua react-router-nativegói.

Để biết thêm thông tin, đừng ngần ngại xem các tài liệu chính thức . Ngoài ra còn có một video được thực hiện bởi một trong những đồng tác giả của thư viện cung cấp một giới thiệu khá thú vị về bộ định tuyến v4, nêu bật một số thay đổi lớn.


2
Tôi đang sử dụng V4 và các hoạt động trên tốt. Tôi đã dành một chút thời gian để tìm hiểu về bộ định tuyến V4 vì có một số lựa chọn lạ nhưng những điều trên chắc chắn hoạt động. Tôi giả sử bạn đang nhập withRoutertừreact-router-dom
Sam Parmenter

3
Tôi đang nhập withRoutertừ react-router-dom. History.push không thay đổi url, nhưng dường như nó không tải <Route>cho đến khi tôi buộc làm mới trang ...
BreakDS

1
@AFiyohmc Tôi đã sai về điều này. Vấn đề là tôi có <Router> bên trong một thành phần React được trang trí @observer, điều này gây ra vấn đề này . Công việc xung quanh là có @withRoutertrên mọi thành phần React như vậy.
BreakDS

3
Đối với những người đi qua câu trả lời tuyệt vời này, withRouterchỉ đơn giản là một HOC sử dụng Routedưới mui xe. Điều đó có nghĩa là nó chỉ sử dụng 3 đạo cụ, lịch sử, trận đấu và địa điểm . Trong ví dụ trên, có vẻ như đó pushlà một chỗ dựa withRoutersẽ thêm vào ButtonToNavigate, nhưng đó không phải là trường hợp. props.history.pushsẽ phải được sử dụng thay thế. Hy vọng điều này sẽ giúp những người khác một chút bối rối.
vinnymac

39
browserHistory.push('/path/some/where')chỉ có vẻ đơn giản hơn nhiều. Các tác giả đang cố gắng ngăn cản lập trình cấp bách, nhưng đôi khi nó chỉ hoạt động tốt hơn!
lux

149

Cách dễ nhất để hoàn thành nó:

this.props.history.push("/new/url")

Ghi chú:

  • Bạn có thể muốn chuyển history proptừ thành phần cha mẹ xuống thành phần bạn muốn gọi hành động nếu nó không khả dụng.

10
Tôi sử dụng bộ định tuyến 4.0, nhưng không có khóa lịch sử trên đạo cụ. Làm thế nào tôi có thể sửa chữa nó?
Nicolas S.Xu

41
Nếu bạn không có this.props.historysẵn trong thành phần của mình thì bạn có thể import {withRouter} from 'react-router-dom'và sau đó export default withRouter(MyComponent)(hoặc const MyComponent = withRouter(...)) và nó sẽ chèn historyvật phẩm vào đạo cụ của thành phần.
Malvineous

@Malvineous thật thú vị, không biết về điều này! Sẽ thử nó!
Jikku Jose

2
Tôi phải thiếu một cái gì đó cơ bản, bởi vì điều này chỉ tốt cho tôi vì vậy tôi không biết tại sao tất cả các câu trả lời yêu cầu giải thích dài dòng như vậy.
Joshua Pinter

làm thế nào để ngăn chặn việc kết nối lại thành phần history.pushvà chỉ kích hoạt cập nhật như khi chúng ta nhấp vào<Link>
Rahul Yadav

55

Tôi gặp vấn đề tương tự khi chuyển sang React-Router v4 vì vậy tôi sẽ cố gắng giải thích giải pháp của mình bên dưới.

Xin đừng coi câu trả lời này là cách giải quyết vấn đề đúng đắn, tôi tưởng tượng sẽ có cơ hội tốt hơn khi React Router v4 trở nên trưởng thành hơn và để lại bản beta (Nó thậm chí có thể tồn tại và tôi chỉ không phát hiện ra nó) .

Đối với ngữ cảnh, tôi gặp vấn đề này vì thỉnh thoảng tôi sử dụng Redux-Sagađể lập trình thay đổi đối tượng lịch sử (giả sử khi người dùng xác thực thành công).

Trong tài liệu Bộ định tuyến React, hãy xem <Router> thành phần và bạn có thể thấy bạn có khả năng vượt qua đối tượng lịch sử của riêng bạn thông qua một chỗ dựa. Đây là bản chất của giải pháp - chúng tôi cung cấp các đối tượng lịch sử để React-Routertừ một thế giới mô-đun.

Các bước:

  1. Cài đặt mô-đun npm lịch sử - yarn add history hoặc npm install history --save
  2. tạo một tệp được gọi history.jstrong App.jsthư mục cấp của bạn (đây là tùy chọn của tôi)

    // src/history.js
    
    import createHistory from 'history/createBrowserHistory';
    export default createHistory();`
  3. Thêm đối tượng lịch sử này vào thành phần Bộ định tuyến của bạn như vậy

    // src/App.js
    
    import history from '../your/path/to/history.js;'
    <Router history={history}>
    // Route tags here
    </Router>
  4. Điều chỉnh URL giống như trước bằng cách nhập đối tượng lịch sử toàn cầu của bạn :

    import history from '../your/path/to/history.js;'
    history.push('new/path/here/');

Mọi thứ nên được đồng bộ hóa ngay bây giờ và bạn cũng có quyền truy cập vào cách thiết lập đối tượng lịch sử theo chương trình và không thông qua một thành phần / vùng chứa.


5
Thay đổi này có hiệu quả với tôi, nhưng chỉ vì tôi đang điều hướng bên ngoài một thành phần. Nếu tôi đang điều hướng bên trong một thành phần như OP, tôi sẽ sử dụng cách tiếp cận được đề xuất bởi @AFiyohmc bằng cách sử dụng các đạo cụ được truyền bởi Routethành phần đó.
Dan Ellis

2
đây là cách tiếp cận được đề xuất kể từ ngày 17/8
Spets

2
@Spets Trong trường hợp của tôi, nếu tôi sử dụng cách tiếp cận này, liên kết sẽ được cập nhật đúng sau khi ấn, nhưng các thành phần không được hiển thị đúng (ví dụ: sau khi cập nhật liên kết, thành phần không được cập nhật trừ khi bạn buộc làm mới trang). Trường hợp bạn thấy rằng đây là cách tiếp cận được đề nghị? Bất kỳ liên kết / nguồn?
mát mẻ

2
@ScottCoates Tôi đã sắp xếp bằng cách sử dụng ví dụ trên, thực sự bằng cách cung cấp lịch sử dưới dạng tham số, nhưng sau khi tôi tự mình gỡ lỗi các mô-đun nút. Có một lỗi phổ biến trên tất cả các trang web, sử dụng nhập "BrowserHistory as Router", thay vào đó, có một đối tượng khác gọi là Router trong phiên bản mới nhất của Reac-router-dom. Sử dụng kết hợp với lịch sử được tạo trong ví dụ trên hoạt động tốt.
mát mẻ

2
url được cập nhật, nhưng trang không được kết xuất dựa trên root mới. Bất kì giải pháp nào? Tại sao tuyến đường kích hoạt là rất khó khăn? Những người thiết kế phản ứng là ra khỏi tâm trí của họ?
Nicolas S.Xu

43

TL; DR:

if (navigate) {
  return <Redirect to="/" push={true} />
}

Câu trả lời đơn giản và khai báo là bạn cần sử dụng <Redirect to={URL} push={boolean} />kết hợp vớisetState()

đẩy: boolean - khi đúng, chuyển hướng sẽ đẩy một mục mới vào lịch sử thay vì thay thế mục hiện tại.


import { Redirect } from 'react-router'

class FooBar extends React.Component {
  state = {
    navigate: false
  }

  render() {
    const { navigate } = this.state

    // here is the important part
    if (navigate) {
      return <Redirect to="/" push={true} />
    }
   // ^^^^^^^^^^^^^^^^^^^^^^^

    return (
      <div>
        <button onClick={() => this.setState({ navigate: true })}>
          Home
        </button>
      </div>
    )
  }
}

Ví dụ đầy đủ ở đây . Đọc thêm ở đây .

Tái bút Ví dụ sử dụng ES7 + Trình khởi tạo thuộc tính để khởi tạo trạng thái. Nhìn vào đây là tốt, nếu bạn quan tâm.


5
Điều này nên được chấp nhận câu trả lời. Giải pháp đơn giản thanh lịch nhất! +1 cho @lustoykov
Ali Abbas Jaffri

1
Tôi cũng đặt điều hướng trở lại thành false trong thành phầnDidUpdate vì nút của tôi nằm trong một tiêu đề và nếu không sẽ chỉ điều hướng một lần.
peterorum

Điều này chỉ hoạt động nếu bạn biết về chuyển hướng khi tải trang. Nếu bạn đang chờ một cuộc gọi không đồng bộ trở lại (nghĩa là xác thực với Google hoặc một cái gì đó) thì bạn sẽ phải sử dụng một trong các history.push()phương thức.
brittohalloran

Không thực sự, bạn vẫn có thể tận dụng tính chất khai báo của phản ứng kết hợp với thành phần <Redirect />. Nếu trang không tải, bạn có thể chuyển sang <Redirect /> khác
Lyubomir

@brittohalloran ý tưởng của phương pháp này bằng bộ định tuyến phản ứng thích hợp, là để đảm bảo bạn sử dụng setState để buộc kết xuất lại.
Ai đó đặc biệt

15

Sử dụng useHistoryhook nếu bạn đang sử dụng các thành phần chức năng

Bạn có thể sử dụng useHistoryhook để lấy historyví dụ.

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

const MyComponent = () => {
  var history = useHistory();

  return (
    <button onClick={() => history.push("/about")}>
      Click me
    </button>
  );
}

Các useHistorymóc cung cấp cho bạn truy cập vào các ví dụ lịch sử mà bạn có thể sử dụng để điều hướng.

Sử dụng thuộc historytính bên trong các thành phần trang

React Router tiêm một số thuộc tính bao gồm historycác thành phần trang.

class HomePage extends React.Component {
  render() {
    const { history } = this.props;

    return (
      <div>
        <button onClick={() => history.push("/projects")}>
          Projects
        </button>
      </div>
    );
  }
}

Bọc các thành phần con withRouter để tiêm thuộc tính bộ định tuyến

withRouterWrapper tiêm thuộc tính bộ định tuyến cho các thành phần. Ví dụ: bạn có thể sử dụng trình bao bọc này để tiêm bộ định tuyến vào thành phần nút đăng xuất được đặt trong menu người dùng.

import { withRouter } from "react-router";

const LogoutButton = withRouter(({ history }) => {
  return (
    <button onClick={() => history.push("/login")}>
      Logout
    </button>
  );
});

export default LogoutButton;

11

Bạn cũng có thể chỉ cần sử dụng đạo cụ để truy cập đối tượng lịch sử: this.props.history.push('new_url')


5
Chỉ hữu ích khi trong thành phần trực tiếp đi xuống từ Bộ định tuyến. Vì sợ bạn chuyển giao lịch sử cho mọi thành phần bạn cần có chức năng này.
mwieczorek

3
Nếu bạn không có this.props.historysẵn trong thành phần của mình thì bạn có thể import {withRouter} from 'react-router-dom'và sau đó export default withRouter(MyComponent)(hoặc const MyComponent = withRouter(...)) và nó sẽ chèn historymục đó vào đạo cụ của thành phần.
Malvineous

9

Bước 1: Chỉ có một thứ để nhập trên đầu trang:

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

Bước 2: Trong Tuyến đường của bạn, vượt qua lịch sử:

<Route
  exact
  path='/posts/add'
  render={({history}) => (
    <PostAdd history={history} />
  )}
/>

Bước 3: lịch sử được chấp nhận như một phần của đạo cụ trong Thành phần tiếp theo, vì vậy bạn có thể chỉ cần:

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

Điều đó thật dễ dàng và thực sự mạnh mẽ.


7

Những công việc này:

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

const SomeComponent = withRouter(({ history }) => (
    <div onClick={() => history.push('/path/some/where')}>
        some clickable element
    </div>); 
);

export default SomeComponent;

5

Câu trả lời của tôi tương tự như của Alex . Tôi không chắc tại sao React-Router lại quá phức tạp. Tại sao tôi phải bọc thành phần của mình bằng HoC chỉ để có quyền truy cập vào những gì thực chất là toàn cầu?

Dù sao, nếu bạn nhìn vào cách họ thực hiện <BrowserRouter>, đó chỉ là một vỏ bọc nhỏ bé xung quanh lịch sử .

Chúng ta có thể lấy lịch sử đó ra để có thể nhập nó từ bất cứ đâu. Tuy nhiên, mẹo là nếu bạn đang thực hiện kết xuất phía máy chủ và bạn thử importmô-đun lịch sử, nó sẽ không hoạt động vì nó sử dụng API chỉ dành cho trình duyệt. Nhưng điều đó không sao vì chúng tôi thường chỉ chuyển hướng theo phản hồi với một nhấp chuột hoặc một số sự kiện phía khách hàng khác. Vì vậy, có thể OK để giả mạo nó:

// history.js
if(__SERVER__) {
    module.exports = {};
} else {
    module.exports = require('history').createBrowserHistory();
}

Với sự trợ giúp của webpack, chúng tôi có thể xác định một số vars để chúng tôi biết chúng tôi đang ở trong môi trường nào:

plugins: [
    new DefinePlugin({
        '__SERVER__': 'false',
        '__BROWSER__': 'true', // you really only need one of these, but I like to have both
    }),

Và bây giờ bạn có thể

import history from './history';

Từ bất kỳ đâu. Nó sẽ chỉ trả về một mô-đun trống trên máy chủ.

Nếu bạn không muốn sử dụng những chiếc lọ ma thuật này, bạn sẽ phải requireở trong đối tượng toàn cầu nơi cần thiết (bên trong bộ xử lý sự kiện của bạn). importsẽ không hoạt động vì nó chỉ hoạt động ở cấp cao nhất.


6
chết tiệt họ làm cho nó quá phức tạp
Abhishek

4
Tôi hoàn toàn đồng ý với bạn. điều này quá phức tạp đối với việc chuyển hướng
Thai Tran

5

Tôi nghĩ rằng @rgommezz bao gồm hầu hết các trường hợp trừ đi một trường hợp mà tôi nghĩ nó khá quan trọng.

// history is already a dependency or React Router, but if don't have it then try npm install save-dev history

import createHistory from "history/createBrowserHistory"

// in your function then call add the below 
const history = createHistory();
// Use push, replace, and go to navigate around.
history.push("/home");

Điều này cho phép tôi viết một dịch vụ đơn giản với các hành động / cuộc gọi mà tôi có thể gọi để thực hiện điều hướng từ bất kỳ thành phần nào tôi muốn mà không cần thực hiện nhiều HoC trên các thành phần của mình ...

Không rõ tại sao không ai cung cấp giải pháp này trước đây. Tôi hy vọng nó có ích, và nếu bạn thấy bất kỳ vấn đề nào với nó xin vui lòng cho tôi biết.


4

Tôi đã thử nghiệm v4 vài ngày nay và .. Tôi yêu nó cho đến nay! Nó chỉ có ý nghĩa sau một thời gian.

Tôi cũng có câu hỏi tương tự và tôi thấy việc xử lý nó giống như cách sau đây hoạt động tốt nhất (và thậm chí có thể là cách nó được dự định). Nó sử dụng trạng thái, một toán tử ternary và <Redirect>.

Trong hàm tạo ()

this.state = {
    redirectTo: null
} 
this.clickhandler = this.clickhandler.bind(this);

Trong kết xuất ()

render(){
    return (
        <div>
        { this.state.redirectTo ?
            <Redirect to={{ pathname: this.state.redirectTo }} /> : 
            (
             <div>
               ..
             <button onClick={ this.clickhandler } />
              ..
             </div>
             )
         }

Trong clickhandler ()

 this.setState({ redirectTo: '/path/some/where' });

Hy vọng nó giúp. Cho tôi biết.


Có bất kỳ cạm bẫy với phương pháp này? Trong dự án của tôi chỉ hoạt động khi tôi đặt trạng thái trong hàm tạo, từ đó tôi có thể chuyển hướng đến bất kỳ trang nào tôi muốn. Nhưng khi tôi đặt trạng thái cho sự kiện (ví dụ, đạo cụ đã thay đổi) Tôi thấy phương thức kết xuất được gọi với trạng thái mới, nhưng chuyển hướng không xảy ra Tôi thấy cùng một trang
Dmitry Malugin

Cạm bẫy là nó sẽ thay thế lịch sử, vì vậy bạn sẽ không thể quay lại - vì vậy về cơ bản, đây không phải là một giải pháp tốt.
dannytenaglias

4

Tôi đã vật lộn với điều này trong một thời gian - một cái gì đó rất đơn giản, nhưng rất phức tạp, bởi vì ReactJS chỉ là một cách viết ứng dụng web hoàn toàn khác, nó rất xa lạ với dân gian xưa của chúng ta!

Tôi đã tạo một thành phần riêng biệt để trừu tượng hóa mớ hỗn độn:

// LinkButton.js

import React from "react";
import PropTypes from "prop-types";
import {Route} from 'react-router-dom';

export default class LinkButton extends React.Component {

    render() {
        return (
            <Route render={({history}) => (
                <button {...this.props}
                       onClick={() => {
                           history.push(this.props.to)
                       }}>
                    {this.props.children}
                </button>
            )}/>
        );
    }
}

LinkButton.propTypes = {
    to: PropTypes.string.isRequired
};

Sau đó thêm nó vào render()phương thức của bạn :

<LinkButton className="btn btn-primary" to="/location">
    Button Text
</LinkButton>

Tôi thấy giải pháp này khá hữu ích. Tôi đang sao chép mã. Hãy cho tôi biết bạn đặt nó trên github - Tôi sẽ trực tiếp gán nó cho bạn.
Abhinav Manchanda

3

Vì không có cách nào khác để đối phó với thiết kế khủng khiếp này, tôi đã viết một thành phần chung sử dụng phương pháp withRouter HOC . Ví dụ dưới đây đang gói một buttonphần tử, nhưng bạn có thể thay đổi thành bất kỳ phần tử có thể nhấp nào bạn cần:

import React from 'react';
import PropTypes from 'prop-types';
import { withRouter } from 'react-router-dom';

const NavButton = (props) => (
  <Button onClick={() => props.history.push(props.to)}>
    {props.children}
  </Button>
);

NavButton.propTypes = {
  history: PropTypes.shape({
    push: PropTypes.func.isRequired
  }),
  to: PropTypes.string.isRequired
};

export default withRouter(NavButton);

Sử dụng:

<NavButton to="/somewhere">Click me</NavButton>

3
this.props.history.push("/url")

Nếu bạn chưa tìm thấy this.props.history có sẵn trong thành phần của bạn, thì hãy thử điều này

import {withRouter} from 'react-router-dom'
export default withRouter(MyComponent)  

Cám ơn rất nhiều!
QauseenMZ

1

Vì đôi khi tôi thích chuyển đổi tuyến đường bằng Ứng dụng sau đó bằng các nút, đây là một ví dụ hoạt động tối thiểu phù hợp với tôi:

import { Component } from 'react'
import { BrowserRouter as Router, Link } from 'react-router-dom'

class App extends Component {
  constructor(props) {
    super(props)

    /** @type BrowserRouter */
    this.router = undefined
  }

  async handleSignFormSubmit() {
    await magic()
    this.router.history.push('/')
  }

  render() {
    return (
      <Router ref={ el => this.router = el }>
        <Link to="/signin">Sign in</Link>
        <Route path="/signin" exact={true} render={() => (
          <SignPage onFormSubmit={ this.handleSignFormSubmit } />
        )} />
      </Router>
    )
  }
}

0

Đối với những người bạn yêu cầu chuyển hướng trước khi kích hoạt hoàn toàn bộ định tuyến bằng cách sử dụng React Routerhoặc React Router DomBạn có thể cung cấp chuyển hướng bằng cách chỉ cần gia nhập đối tượng lịch sử và đẩy trạng thái mới vào trong cấu trúc của bạn app.js. Hãy xem xét những điều sau đây:

function getSubdomain(hostname) {
    let regexParse = new RegExp('[a-z\-0-9]{2,63}\.[a-z\.]{2,5}$');
    let urlParts = regexParse.exec(hostname);
    return hostname.replace(urlParts[0], '').slice(0, -1);
}

class App extends Component {

    constructor(props) {
        super(props);


        this.state = {
            hostState: true
        };

        if (getSubdomain(window.location.hostname).length > 0) {
            this.state.hostState = false;
            window.history.pushState('', '', './login');
        } else {
            console.log(getSubdomain(window.location.hostname));
        }

    }


    render() {
        return (

            <BrowserRouter>
                {this.state.hostState ? (
                    <div>
                        <Route path="/login" component={LoginContainer}/>
                        <Route path="/" component={PublicContainer}/>
                    </div>
                ) : (
                    <div>
                        <Route path="/login" component={LoginContainer}/>
                    </div>
                )

                }
            </BrowserRouter>)
    }


}

Ở đây, chúng tôi muốn thay đổi các Tuyến đầu ra phụ thuộc vào một tên miền phụ, bằng cách tương tác với đối tượng lịch sử trước khi thành phần kết xuất, chúng tôi có thể chuyển hướng một cách hiệu quả trong khi vẫn giữ nguyên các tuyến đường của mình.

window.history.pushState('', '', './login');
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.