閲覧履歴に応じて、いくつかのビジネスロジックを実装する必要があります。
私がやりたいのは次のようなものです。
reactRouter.onUrlChange(url => {
this.history.push(url);
});
URLが更新されたときにreact-routerからコールバックを受信する方法はありますか?
閲覧履歴に応じて、いくつかのビジネスロジックを実装する必要があります。
私がやりたいのは次のようなものです。
reactRouter.onUrlChange(url => {
this.history.push(url);
});
URLが更新されたときにreact-routerからコールバックを受信する方法はありますか?
回答:
history.listen()
ルート変更を検出しようとするときに機能を利用することができます。を使用していることを考慮してreact-router v4
、コンポーネントをwithRouter
HOCでラップして、history
小道具にアクセスします。
history.listen()
unlisten
関数を返します。あなたはこれをunregister
聞いてから使うでしょう。
次のようにルートを構成できます
index.js
ReactDOM.render(
<BrowserRouter>
<AppContainer>
<Route exact path="/" Component={...} />
<Route exact path="/Home" Component={...} />
</AppContainer>
</BrowserRouter>,
document.getElementById('root')
);
そして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);
履歴ドキュメントから:
次を使用して、現在の場所への変更をリッスンできます
history.listen
。
history.listen((location, action) => { console.log(`The current URL is ${location.pathname}${location.search}${location.hash}`) console.log(`The last navigation action was ${action}`) })
ロケーションオブジェクトは、以下を含むwindow.locationインターフェイスのサブセットを実装します。
**location.pathname** - The path of the URL **location.search** - The URL query string **location.hash** - The URL hash fragment
場所には、次のプロパティもあります。
location.state -URLに存在しないこの場所の追加の状態(
createBrowserHistory
およびで サポートされていますcreateMemoryHistory
)
location.key
-この場所を表す一意の文字列(createBrowserHistory
およびでサポートされていますcreateMemoryHistory
)アクションは
PUSH, REPLACE, or POP
、ユーザーが現在のURLにアクセスした方法に応じたものです。
react-router v3を使用している場合はhistory.listen()
、history
上記のようにパッケージから使用することも、使用することもできます。browserHistory.listen()
次のようなルートを構成して使用できます
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>
)
}
}
react-router v4
」
withRouter
history.listen()
してwithRouter
いません...また、ルーティングが発生するたびに、コンポーネントを新しい小道具で既に更新している場合、なぜ使用するのでしょうか。nextProps.location.href === this.props.location.href
incomponentWillUpdate
を簡単に比較して、変更された場合に必要なことをすべて実行できます。
history
オブジェクトをグローバルにリッスンする場合は、自分でオブジェクトを作成して、に渡す必要がありRouter
ます。次に、そのlisten()
方法でそれを聞くことができます:
// 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>
履歴オブジェクトをモジュールとして作成するとさらに良いので、必要な場所に簡単にインポートできます(例: import history from './history';
react-router v6
今後のv6では、これはuseLocation
とuseEffect
フックを組み合わせることで実行できます。
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])
...
}
便利な再利用のために、カスタムuseLocationChange
フックでこれを行うことができます
// 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)
})
...
}
変更時に前のルートも確認する必要がある場合は、usePrevious
フックと組み合わせることができます
const 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)
})
...
}
マウントされている最初のクライアントルートで上記のすべてが発生し、その後の変更に注意することが重要です。それが問題である場合は、後者の例を使用して、prevLocation
何かを行う前にが存在することを確認してください。
location
ここで明確にするためにブラウザの場所があるので、それはすべてのコンポーネントで同じであり、その意味で常に正しいです。異なるコンポーネントでフックを使用する場合、場所が変更されたときにそれらはすべて同じ値を受け取ります。彼らがその情報をどうするかは違うと思いますが、それは常に一貫しています。
これは古い質問であり、ルート変更をプッシュするためにルート変更をリッスンするビジネスニーズを完全には理解していません。ラウンドアバウトのようです。
しかし'page_path'
、グーグルアナリティクス/グローバルサイトタグ/同様のもののreact-routerルート変更を更新することだけが必要だったためにここにたどり着いた場合は、ここで使用できるフックがあります。私は受け入れられた答えに基づいてそれを書きました:
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])
}
このフックは、アプリの上部近くにあるがルーター内で1回使用する必要があります。私はそれApp.js
を次のようにしています:
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>
)
Reactシングルページアプリで新しい画面に移動した後、ChromeVoxスクリーンリーダーを「画面」の上部にフォーカスしようとしたときに、この質問に遭遇しました。基本的に、サーバーでレンダリングされた新しいWebページへのリンクをたどって、このページが読み込まれた場合に何が起こるかをエミュレートしようとします。
このソリューションはリスナーを必要とせずwithRouter()
、componentDidUpdate()
ライフサイクルメソッドを使用してクリックをトリガーし、新しいURLパスに移動するときにChromeVoxを目的の要素にフォーカスします。
すべてのアプリ画面を含むreact-routerスイッチタグをラップする「Screen」コンポーネントを作成しました。
<Screen>
<Switch>
... add <Route> for each screen here...
</Switch>
</Screen>
Screen.tsx
成分注:このコンポーネントは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)
のfocus()
代わりにを使用してみましたclick()
が、クリックするとChromeVoxは現在読み取っている内容の読み取りを停止し、開始するように指示したところから再開します。
高度な注意:このソリューションでは<nav>
、Screenコンポーネント内で<main>
コンテンツの後にレンダリングされるナビゲーションは、main
cssを使用して視覚的に上に配置されますorder: -1;
。したがって、擬似コードでは:
<Screen style={{ display: 'flex' }}>
<main>
<nav style={{ order: -1 }}>
<Screen>
このソリューションについての考え、コメント、またはヒントがある場合は、コメントを追加してください。
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])
}