Saya harus menerapkan beberapa logika bisnis tergantung pada riwayat penelusuran.
Yang ingin saya lakukan adalah seperti ini:
reactRouter.onUrlChange(url => {
this.history.push(url);
});
Apakah ada cara untuk menerima panggilan balik dari react-router ketika URL diperbarui?
Jawaban:
Anda dapat menggunakan
history.listen()
fungsi saat mencoba mendeteksi perubahan rute. Mengingat Anda sedang menggunakanreact-router v4
, bungkus komponen Anda denganwithRouter
HOC untuk mendapatkan akses kehistory
prop.history.listen()
mengembalikan suatuunlisten
fungsi. Anda akan menggunakan ini untukunregister
mendengarkan.Anda dapat mengonfigurasi rute Anda seperti
index.js
ReactDOM.render( <BrowserRouter> <AppContainer> <Route exact path="/" Component={...} /> <Route exact path="/Home" Component={...} /> </AppContainer> </BrowserRouter>, document.getElementById('root') );
dan kemudian di AppContainer.js
class App extends Component { componentWillMount() { this.unlisten = this.props.history.listen((location, action) => { console.log("on route change"); }); } componentWillUnmount() { this.unlisten(); } render() { return ( <div>{this.props.children}</div> ); } } export default withRouter(App);
Dari dokumen sejarah :
Ketika Anda menggunakan react-router v3 Anda dapat menggunakan
history.listen()
darihistory
paket seperti yang disebutkan di atas atau Anda juga dapat menggunakannyabrowserHistory.listen()
Anda dapat mengonfigurasi dan menggunakan rute Anda seperti
import {browserHistory} from 'react-router'; class App extends React.Component { componentDidMount() { this.unlisten = browserHistory.listen( location => { console.log('route changes'); }); } componentWillUnmount() { this.unlisten(); } render() { return ( <Route path="/" onChange={yourHandler} component={AppContainer}> <IndexRoute component={StaticContainer} /> <Route path="/a" component={ContainerA} /> <Route path="/b" component={ContainerB} /> </Route> ) } }
sumber
react-router v4
"withRouter
history.listen()
saat menggunakanwithRouter
sudah memperbarui komponen Anda dengan alat peraga baru setiap kali perutean terjadi? Anda bisa melakukan perbandingan sederhana darinextProps.location.href === this.props.location.href
dalamcomponentWillUpdate
untuk melakukan sesuatu yang perlu Anda lakukan jika itu telah berubah.Pembaruan untuk React Router 5.1.
import React from 'react'; import { useLocation, Switch } from 'react-router-dom'; const App = () => { const location = useLocation(); React.useEffect(() => { console.log('Location changed'); }, [location]); return ( <Switch> {/* Routes go here */} </Switch> ); };
sumber
Jika Anda ingin mendengarkan
history
objek secara global, Anda harus membuatnya sendiri dan meneruskannya keRouter
. Kemudian Anda dapat mendengarkannya denganlisten()
metodenya:// Use Router from react-router, not BrowserRouter. import { Router } from 'react-router'; // Create history object. import createHistory from 'history/createBrowserHistory'; const history = createHistory(); // Listen to history changes. // You can unlisten by calling the constant (`unlisten()`). const unlisten = history.listen((location, action) => { console.log(action, location.pathname, location.state); }); // Pass history to Router. <Router history={history}> ... </Router>
Lebih baik lagi jika Anda membuat objek riwayat sebagai modul, sehingga Anda dapat dengan mudah mengimpornya di mana pun Anda membutuhkannya (mis
import history from './history';
sumber
react-router v6
Di v6 mendatang , ini bisa dilakukan dengan menggabungkan hook
useLocation
danuseEffect
import { useLocation } from 'react-router-dom'; const MyComponent = () => { const location = useLocation() React.useEffect(() => { // runs on location, i.e. route, change console.log('handle route change here', location) }, [location]) ... }
Untuk penggunaan kembali yang nyaman, Anda dapat melakukannya di
useLocationChange
hook khusus// runs action(location) on location, i.e. route, change const useLocationChange = (action) => { const location = useLocation() React.useEffect(() => { action(location) }, [location]) } const MyComponent1 = () => { useLocationChange((location) => { console.log('handle route change here', location) }) ... } const MyComponent2 = () => { useLocationChange((location) => { console.log('and also here', location) }) ... }
Jika Anda juga perlu melihat rute sebelumnya pada perubahan, Anda dapat menggabungkan dengan
usePrevious
kailconst usePrevious(value) { const ref = React.useRef() React.useEffect(() => { ref.current = value }) return ref.current } const useLocationChange = (action) => { const location = useLocation() const prevLocation = usePrevious(location) React.useEffect(() => { action(location, prevLocation) }, [location]) } const MyComponent1 = () => { useLocationChange((location, prevLocation) => { console.log('changed from', prevLocation, 'to', location) }) ... }
Penting untuk dicatat bahwa semua api di atas pada rute klien pertama sedang dipasang, serta perubahan selanjutnya. Jika itu masalah, gunakan contoh terakhir dan periksa apakah
prevLocation
ada sebelum melakukan apa pun.sumber
location
sini adalah lokasi browser, jadi sama di setiap komponen dan selalu benar dalam hal itu. Jika Anda menggunakan hook di berbagai komponen, mereka semua akan menerima nilai yang sama saat lokasi berubah. Saya kira apa yang mereka lakukan dengan info itu akan berbeda, tetapi selalu konsisten.Ini adalah pertanyaan lama dan saya tidak begitu memahami kebutuhan bisnis untuk mendengarkan perubahan rute untuk mendorong perubahan rute; sepertinya bundaran.
TAPI jika Anda berakhir di sini karena yang Anda inginkan hanyalah memperbarui
'page_path'
perubahan rute react-router untuk google analytics / tag situs global / sesuatu yang serupa, inilah hook yang sekarang dapat Anda gunakan. Saya menulisnya berdasarkan jawaban yang diterima:useTracking.js
import { useEffect } from 'react' import { useHistory } from 'react-router-dom' export const useTracking = (trackingId) => { const { listen } = useHistory() useEffect(() => { const unlisten = listen((location) => { // if you pasted the google snippet on your index.html // you've declared this function in the global if (!window.gtag) return window.gtag('config', trackingId, { page_path: location.pathname }) }) // remember, hooks that add listeners // should have cleanup to remove them return unlisten }, [trackingId, listen]) }
Anda harus menggunakan pengait ini sekali di aplikasi Anda, di suatu tempat di dekat bagian atas tetapi masih di dalam router. Saya memilikinya di
App.js
yang terlihat seperti ini:App.js
import * as React from 'react' import { BrowserRouter, Route, Switch } from 'react-router-dom' import Home from './Home/Home' import About from './About/About' // this is the file above import { useTracking } from './useTracking' export const App = () => { useTracking('UA-USE-YOURS-HERE') return ( <Switch> <Route path="/about"> <About /> </Route> <Route path="/"> <Home /> </Route> </Switch> ) } // I find it handy to have a named export of the App // and then the default export which wraps it with // all the providers I need. // Mostly for testing purposes, but in this case, // it allows us to use the hook above, // since you may only use it when inside a Router export default () => ( <BrowserRouter> <App /> </BrowserRouter> )
sumber
Saya menemukan pertanyaan ini saat saya mencoba memfokuskan pembaca layar ChromeVox ke bagian atas "layar" setelah menavigasi ke layar baru di aplikasi satu halaman React. Pada dasarnya mencoba meniru apa yang akan terjadi jika halaman ini dimuat dengan mengikuti link ke halaman web baru yang dirender server.
Solusi ini tidak memerlukan pendengar, ia menggunakan
withRouter()
dancomponentDidUpdate()
metode siklus hidup untuk memicu klik untuk memfokuskan ChromeVox ke elemen yang diinginkan saat menavigasi ke jalur url baru.Penerapan
Saya membuat komponen "Layar" yang dibungkus di sekitar tag saklar react-router yang berisi semua layar aplikasi.
<Screen> <Switch> ... add <Route> for each screen here... </Switch> </Screen>
Screen.tsx
KomponenCatatan: Komponen ini menggunakan React + TypeScript
import React from 'react' import { RouteComponentProps, withRouter } from 'react-router' class Screen extends React.Component<RouteComponentProps> { public screen = React.createRef<HTMLDivElement>() public componentDidUpdate = (prevProps: RouteComponentProps) => { if (this.props.location.pathname !== prevProps.location.pathname) { // Hack: setTimeout delays click until end of current // event loop to ensure new screen has mounted. window.setTimeout(() => { this.screen.current!.click() }, 0) } } public render() { return <div ref={this.screen}>{this.props.children}</div> } } export default withRouter(Screen)
Saya telah mencoba menggunakan
focus()
alih-alihclick()
, tetapi klik menyebabkan ChromeVox berhenti membaca apa pun yang sedang dibaca dan mulai lagi di mana saya menyuruhnya untuk memulai.Catatan lanjutan: Dalam solusi ini, navigasi
<nav>
yang berada di dalam komponen Layar dan dirender setelah<main>
konten secara visual ditempatkan di atasmain
menggunakan cssorder: -1;
. Jadi dalam kode pseudo:<Screen style={{ display: 'flex' }}> <main> <nav style={{ order: -1 }}> <Screen>
Jika Anda memiliki pemikiran, komentar, atau tip tentang solusi ini, silakan tambahkan komentar.
sumber
Bereaksi Router V5
Jika Anda ingin pathName sebagai string ('/' atau 'users'), Anda dapat menggunakan berikut ini:
// React Hooks: React Router DOM let history = useHistory(); const location = useLocation(); const pathName = location.pathname;
sumber
import React from 'react'; import { BrowserRouter as Router, Switch, Route } from 'react-router-dom'; import Sidebar from './Sidebar'; import Chat from './Chat'; <Router> <Sidebar /> <Switch> <Route path="/rooms/:roomId" component={Chat}> </Route> </Switch> </Router>
import { useHistory } from 'react-router-dom'; function SidebarChat(props) { **const history = useHistory();** var openChat = function (id) { **//To navigate** history.push("/rooms/" + id); } }
**//To Detect the navigation change or param change** import { useParams } from 'react-router-dom'; function Chat(props) { var { roomId } = useParams(); var roomId = props.match.params.roomId; useEffect(() => { //Detect the paramter change }, [roomId]) useEffect(() => { //Detect the location/url change }, [location]) }
sumber