Yanıtlar:
Prop withRouter
almak için kullanırım location
. Bileşen yeni bir rota nedeniyle güncellendiğinde, değerin değişip değişmediğini kontrol ederim:
@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>
}
}
Umarım yardımcı olur
withRouter
ama hata alıyorum You should not use <Route> or withRouter() outside a <Router>
. <Router/>
Yukarıdaki kodda herhangi bir bileşen görmüyorum . Peki nasıl çalışıyor?
<Switch>
bileşen fiili yönlendirici görevi görüyor. Yalnızca <Route>
eşleşen bir yola sahip olan ilk giriş işlenecektir. <Router/>
Bu senaryoda herhangi bir bileşene gerek yok
Yukarıdakileri genişletmek için geçmiş nesnesine gitmeniz gerekir. Kullanıyorsanız , geçmiş nesnesinin özelliklerine ve işlevlerine props aracılığıyla erişim sağlamak için bileşeninizi daha yüksek dereceli bir bileşenle (HoC)BrowserRouter
içe aktarabilir withRouter
ve sarabilirsiniz .
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);
Dikkat edilmesi gereken tek şey, Router ve diğer birçok yolla history
nesnenin yapısını bozarken nesneyi kirletmesidir.
withRoutes
için withRouter
.
History v4 lib kullanmalısınız .
Oradan örnek
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.push
tetikleyici gibi görünüyor history.listen
. Geçmiş v4 belgelerinde Temel URL kullanma örneğine bakın . Bu aslında bir tarayıcının yerel nesnesinin bir sarmalayıcısı olduğundan, tam olarak yerel olan gibi davranmaz. history
history
const unlisten = history.listen(myListener); unlisten();
withRouter
, history.listen
ve useEffect
(React Hooks) birlikte oldukça güzel çalışıyor:
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)
Dinleyici geri araması, bir rota değiştirildiğinde her seferinde tetiklenir ve bunun dönüşü history.listen
, iyi bir şekilde oynayan bir kapatma işleyicisidir useEffect
.
v5.1 kullanışlı kancayı tanıtıyor useLocation
https://reacttraining.com/blog/react-router-v5-1/#uselocation
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
. UseLocation () çağrısının, yönlendiriciyi ağaca yerleştiren aynı bileşende olmadığından emin olmanız gerekir: buraya bakın
Kancalı:
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)
<DebugHistory>
Bileşen olarak içe aktar ve işle
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]);
}
kancalı
Bazı durumlarda şu şekilde render
yerine öznitelik kullanabilirsiniz component
:
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>
}
}
onRouteChange
Yöntemdeki durumu değiştirirseniz , bunun 'Maksimum güncelleme derinliği aşıldı' hatasına neden olabileceğine dikkat edin .
React Hooks ile kullanıyorum 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])
useEffect
Kanca ile bir dinleyici eklemeden rota değişikliklerini tespit etmek mümkündür.
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);
Bu problemle az önce uğraştım, bu yüzden verilen diğer cevaplara ek olarak çözümümü ekleyeceğim.
Buradaki sorun useEffect
, çağrı yalnızca ilk işlemden sonra tetiklendiğinden, istenmeyen bir gecikme olduğundan, gerçekten istediğiniz gibi çalışmamasıdır.
Redux gibi bir durum yöneticisi kullanırsanız, mağazadaki durum nedeniyle ekranda bir titreme yaşama ihtimaliniz vardır.
useLayoutEffect
Bu hemen tetiklendiği için gerçekten istediğiniz şey kullanmaktır .
Bu yüzden yönlendiricimle aynı dizine koyduğum küçük bir yardımcı program işlevi yazdım:
export const callApis = (fn, path) => {
useLayoutEffect(() => {
fn();
}, [path]);
};
HOC bileşeni içinden şöyle çağırıyorum:
callApis(() => getTopicById({topicId}), path);
path
match
kullanılırken nesnede geçirilen prop withRouter
.
Tarihi elle dinlemekten / dinlemekten gerçekten yana değilim. Bu sadece imo.