ฉันต้องใช้ตรรกะทางธุรกิจบางอย่างขึ้นอยู่กับประวัติการเข้าชม
สิ่งที่ฉันต้องการทำมีดังนี้:
reactRouter.onUrlChange(url => {
this.history.push(url);
});
มีวิธีใดบ้างในการรับการติดต่อกลับจาก react-router เมื่อ URL ได้รับการอัปเดต
ฉันต้องใช้ตรรกะทางธุรกิจบางอย่างขึ้นอยู่กับประวัติการเข้าชม
สิ่งที่ฉันต้องการทำมีดังนี้:
reactRouter.onUrlChange(url => {
this.history.push(url);
});
มีวิธีใดบ้างในการรับการติดต่อกลับจาก react-router เมื่อ URL ได้รับการอัปเดต
คำตอบ:
คุณสามารถใช้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
ในการcomponentWillUpdate
ที่จะดำเนินการสิ่งที่คุณต้องการจะทำอย่างไรถ้ามีการเปลี่ยนแปลง
อัปเดตสำหรับ 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>
);
};
หากคุณต้องการฟัง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'
เปลี่ยนแปลงเส้นทางในการตอบสนองเราเตอร์สำหรับ Google Analytics / แท็กเว็บไซต์ทั่วโลก / สิ่งที่คล้ายกันที่นี่เป็นตะขอที่คุณสามารถใช้ในขณะนี้ ฉันเขียนตามคำตอบที่ยอมรับ:
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])
}
คุณควรใช้เบ็ดนี้หนึ่งครั้งในแอพของคุณที่ไหนสักแห่งใกล้ด้านบน แต่ยังอยู่ในเราเตอร์ ฉันมีมัน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>
)
ฉันเจอคำถามนี้ขณะที่พยายามโฟกัสโปรแกรมอ่านหน้าจอ ChromeVox ไปที่ด้านบนของ "หน้าจอ" หลังจากไปที่หน้าจอใหม่ในแอป React หน้าเดียว โดยทั่วไปจะพยายามเลียนแบบสิ่งที่จะเกิดขึ้นหากหน้านี้โหลดโดยไปที่ลิงก์ไปยังหน้าเว็บที่แสดงผลเซิร์ฟเวอร์ใหม่
โซลูชันนี้ไม่ต้องการผู้ฟังใด ๆ ใช้withRouter()
และcomponentDidUpdate()
วิธีวงจรชีวิตในการกระตุ้นให้คลิกเพื่อโฟกัส ChromeVox ไปที่องค์ประกอบที่ต้องการเมื่อไปยังเส้นทาง URL ใหม่
ฉันสร้างส่วนประกอบ "หน้าจอ" ซึ่งล้อมรอบแท็กสวิตช์ตอบสนองเราเตอร์ซึ่งมีหน้าจอแอปทั้งหมด
<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>
ซึ่งภายในส่วนประกอบหน้าจอแสดงผลและหลังจากที่<main>
เนื้อหาอยู่ในตำแหน่งที่มองเห็นข้างต้นmain
ใช้ order: -1;
CSS ดังนั้นในรหัสหลอก:
<Screen style={{ display: 'flex' }}>
<main>
<nav style={{ order: -1 }}>
<Screen>
หากคุณมีความคิดความคิดเห็นหรือเคล็ดลับเกี่ยวกับโซลูชันนี้โปรดเพิ่มความคิดเห็น
ตอบสนองเราเตอร์ V5.0
หากคุณต้องการให้ pathName เป็นสตริง ('/' หรือ 'users') คุณสามารถใช้สิ่งต่อไปนี้:
// React Hooks: React Router DOM
let history = useHistory();
const location = useLocation();
const pathName = location.pathname;
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])
}