Jawaban:
Saya gunakan withRouteruntuk mendapatkan locationprop. Ketika komponen diperbarui karena rute baru, saya memeriksa apakah nilainya berubah:
@withRouter
class App extends React.Component {
static propTypes = {
location: React.PropTypes.object.isRequired
}
// ...
componentDidUpdate(prevProps) {
if (this.props.location !== prevProps.location) {
this.onRouteChanged();
}
}
onRouteChanged() {
console.log("ROUTE CHANGED");
}
// ...
render(){
return <Switch>
<Route path="/" exact component={HomePage} />
<Route path="/checkout" component={CheckoutPage} />
<Route path="/success" component={SuccessPage} />
// ...
<Route component={NotFound} />
</Switch>
}
}
Semoga ini bisa membantu
withRouter, tetapi saya mendapatkan kesalahan You should not use <Route> or withRouter() outside a <Router>. Saya tidak melihat <Router/>komponen dalam kode di atas. Jadi bagaimana cara kerjanya?
<Switch>komponen tersebut bertindak sebagai router de-facto. Hanya <Route>entri pertama yang memiliki jalur yang cocok, akan diberikan. Tidak perlu <Router/>komponen apa pun dalam skenario ini
Untuk memperluas di atas, Anda harus mendapatkan objek sejarah. Jika Anda menggunakan BrowserRouter, Anda dapat mengimpor withRouterdan membungkus komponen Anda dengan komponen orde tinggi (HoC) agar memiliki akses melalui alat peraga ke properti dan fungsi objek sejarah.
import { withRouter } from 'react-router-dom';
const myComponent = ({ history }) => {
history.listen((location, action) => {
// location is an object like window.location
console.log(action, location.pathname, location.state)
});
return <div>...</div>;
};
export default withRouter(myComponent);
Satu-satunya hal yang perlu diperhatikan adalah bahwa denganouter dan sebagian besar cara lain untuk mengakses historytampaknya mencemari alat peraga ketika mereka de-struktur objek ke dalamnya.
withRoutesuntuk withRouter.
Anda harus menggunakan riwayat v4 lib.
Contoh dari sana
history.listen((location, action) => {
console.log(`The current URL is ${location.pathname}${location.search}${location.hash}`)
console.log(`The last navigation action was ${action}`)
})
history.pushmemicu history.listen. Lihat contoh Menggunakan URL Pangkalan di riwayat v4 docs . Karena itu historysebenarnya pembungkus historyobjek asli browser, itu tidak berperilaku persis seperti yang asli.
const unlisten = history.listen(myListener); unlisten();
withRouter,, history.listendan useEffect(React Hooks) bekerja sangat baik bersama-sama:
import React, { useEffect } from 'react'
import { withRouter } from 'react-router-dom'
const Component = ({ history }) => {
useEffect(() => history.listen(() => {
// do something on route change
// for my example, close a drawer
}), [])
//...
}
export default withRouter(Component)
Panggilan balik pendengar akan diaktifkan setiap kali rute diubah, dan pengembaliannya history.listenadalah penangan shutdown yang bekerja dengan baik useEffect.
v5.1 memperkenalkan kait berguna useLocation
https://reacttraining.com/blog/react-router-v5-1/#uselokasi
import { Switch, useLocation } from 'react-router-dom'
function usePageViews() {
let location = useLocation()
useEffect(
() => {
ga.send(['pageview', location.pathname])
},
[location]
)
}
function App() {
usePageViews()
return <Switch>{/* your routes here */}</Switch>
}
Cannot read property 'location' of undefined at useLocation. Anda perlu memastikan bahwa panggilan useLocation () tidak berada di komponen yang sama dengan yang menempatkan router ke pohon: lihat di sini
Dengan kait:
import { useEffect } from 'react'
import { withRouter } from 'react-router-dom'
import { history as historyShape } from 'react-router-prop-types'
const DebugHistory = ({ history }) => {
useEffect(() => {
console.log('> Router', history.action, history.location])
}, [history.location.key])
return null
}
DebugHistory.propTypes = { history: historyShape }
export default withRouter(DebugHistory)
Impor dan render sebagai <DebugHistory>komponen
import React, { useEffect } from 'react';
import { useLocation } from 'react-router';
function MyApp() {
const location = useLocation();
useEffect(() => {
console.log('route has been changed');
...your code
},[location.pathname]);
}
dengan kait
Dengan Hooks bereaksi, saya menggunakan useEffect
const history = useHistory()
const queryString = require('query-string')
const parsed = queryString.parse(location.search)
const [search, setSearch] = useState(parsed.search ? parsed.search : '')
useEffect(() => {
const parsedSearch = parsed.search ? parsed.search : ''
if (parsedSearch !== search) {
// do some action! The route Changed!
}
}, [location.search])
Dalam beberapa kasus, Anda mungkin menggunakan renderatribut alih-alih component, dengan cara ini:
class App extends React.Component {
constructor (props) {
super(props);
}
onRouteChange (pageId) {
console.log(pageId);
}
render () {
return <Switch>
<Route path="/" exact render={(props) => {
this.onRouteChange('home');
return <HomePage {...props} />;
}} />
<Route path="/checkout" exact render={(props) => {
this.onRouteChange('checkout');
return <CheckoutPage {...props} />;
}} />
</Switch>
}
}
Perhatikan bahwa jika Anda mengubah status dalam onRouteChangemetode, ini dapat menyebabkan kesalahan 'Kedalaman pembaruan maksimum terlampaui'.
Dengan useEffectkait itu mungkin untuk mendeteksi perubahan rute tanpa menambahkan pendengar.
import React, { useEffect } from 'react';
import { Switch, Route, withRouter } from 'react-router-dom';
import Main from './Main';
import Blog from './Blog';
const App = ({history}) => {
useEffect( () => {
// When route changes, history.location.pathname changes as well
// And the code will execute after this line
}, [history.location.pathname]);
return (<Switch>
<Route exact path = '/' component = {Main}/>
<Route exact path = '/blog' component = {Blog}/>
</Switch>);
}
export default withRouter(App);
Saya hanya berurusan dengan masalah ini, jadi saya akan menambahkan solusi saya sebagai suplemen pada jawaban lain yang diberikan.
Masalahnya di sini adalah bahwa useEffecttidak benar-benar berfungsi seperti yang Anda inginkan, karena panggilan hanya akan dipicu setelah render pertama sehingga ada penundaan yang tidak diinginkan.
Jika Anda menggunakan beberapa pengelola negara seperti redux, kemungkinan Anda akan mendapatkan layar berkedip karena keadaan yang tersisa di toko.
Apa yang benar-benar Anda inginkan adalah menggunakan useLayoutEffectkarena ini akan segera dipicu.
Jadi saya menulis fungsi utilitas kecil yang saya taruh di direktori yang sama dengan router saya:
export const callApis = (fn, path) => {
useLayoutEffect(() => {
fn();
}, [path]);
};
Yang saya panggil dari dalam komponen HOC seperti ini:
callApis(() => getTopicById({topicId}), path);
pathadalah penyangga yang dilewatkan di matchobjek saat menggunakan withRouter.
Saya tidak terlalu suka mendengarkan / tidak mendengarkan secara manual tentang sejarah. Itu hanya imo.