Mam kilka przycisków, które działają jak trasy. Za każdym razem, gdy zmienia się trasa, chcę się upewnić, że aktywny przycisk się zmienia.
Czy istnieje sposób, aby nasłuchiwać zmian tras w React Router v4?
react-router-v4
Kasper
źródło
źródło
Odpowiedzi:
Używam
withRouter
do zdobycialocation
rekwizytu. Kiedy komponent jest aktualizowany z powodu nowej trasy, sprawdzam, czy zmieniła się wartość:Mam nadzieję, że to pomoże
źródło
withRouter
, ale pojawia się błądYou should not use <Route> or withRouter() outside a <Router>
. Nie widzę żadnego<Router/>
komponentu w powyższym kodzie. Jak to działa?<Switch>
komponent działa jako de facto router.<Route>
Wyrenderowany zostanie tylko pierwszy wpis, który ma pasującą ścieżkę. W<Router/>
tym scenariuszu nie jest potrzebny żaden komponentAby rozwinąć powyższe, musisz dostać się do obiektu historii. Jeśli używasz
BrowserRouter
, możesz zaimportowaćwithRouter
i opakować swój komponent komponentem wyższego rzędu (HoC) , aby mieć dostęp poprzez właściwości do właściwości i funkcji obiektu historii.Jedyną rzeczą, o której należy pamiętać, jest to, że przy użyciu routera i większości innych sposobów uzyskiwania dostępu do obiektów
history
zdaje się, że zanieczyszczają one właściwości, gdy przekształcają one obiekt w jego strukturę.źródło
withRoutes
sięwithRouter
.history
a nie zmiennalisten
.Powinieneś użyć historii v4 lib.
Przykład z tego miejsca
źródło
history.push
wyzwalahistory.listen
. Zobacz przykład użycia podstawowego adresu URL w dokumentach historii v4 . Ponieważhistory
jest to w rzeczywistości opakowanie natywnegohistory
obiektu przeglądarki, nie zachowuje się dokładnie tak, jak natywny.const unlisten = history.listen(myListener); unlisten();
withRouter
,history.listen
iuseEffect
(React Hooks) całkiem dobrze razem współpracują:Wywołanie zwrotne listenera zostanie uruchomione za każdym razem, gdy zostanie zmieniona trasa, a zwrotem dla
history.listen
jest program obsługi zamykania, z którym dobrze się bawiuseEffect
.źródło
Wersja 5.1 wprowadza przydatny hak
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> }
źródło
Cannot read property 'location' of undefined at useLocation
. Musisz się upewnić, że wywołanie useLocation () nie znajduje się w tym samym komponencie, który umieszcza router w drzewie: patrz tutajz haczykami
źródło
react-router-dom
zamiastreact-router
Z haczykami:
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)
Importuj i renderuj jako
<DebugHistory>
komponentźródło
import { useHistory } from 'react-router-dom'; const Scroll = () => { const history = useHistory(); useEffect(() => { window.scrollTo(0, 0); }, [history.location.pathname]); return null; }
źródło
Korzystam z React Hooks
useEffect
źródło
W przypadku komponentów funkcjonalnych spróbuj useEffect z props.location.
źródło
W niektórych przypadkach możesz użyć
render
atrybutu zamiastcomponent
, w ten sposób:Zwróć uwagę, że jeśli zmienisz stan
onRouteChange
metody, może to spowodować błąd „Przekroczono maksymalną głębokość aktualizacji”.źródło
Dzięki
useEffect
hakowi można wykryć zmiany trasy bez dodawania nasłuchiwania.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);
źródło
Właśnie poradziłem sobie z tym problemem, więc dodam moje rozwiązanie jako uzupełnienie innych udzielonych odpowiedzi.
Problem polega na tym,
useEffect
że nie działa tak, jak byś tego chciał, ponieważ wywołanie jest wyzwalane dopiero po pierwszym renderowaniu, więc występuje niepożądane opóźnienie.Jeśli używasz jakiegoś menedżera stanu, takiego jak redux, istnieje prawdopodobieństwo, że pojawi się migotanie na ekranie z powodu utrzymującego się stanu w sklepie.
To, czego naprawdę chcesz, to użyć
useLayoutEffect
ponieważ jest to uruchamiane natychmiast.Napisałem więc małą funkcję narzędzia, którą umieściłem w tym samym katalogu co mój router:
Które dzwonię z poziomu HOC komponentu w ten sposób:
path
to właściwość, która jest przekazywana wmatch
obiekcie podczas używaniawithRouter
.Nie jestem zwolennikiem ręcznego odsłuchiwania / nieposłuchiwania historii. To tylko imo.
źródło