উত্তর:
আমি প্রপস withRouter
পেতে ব্যবহার location
। নতুন রুটের কারণে যখন উপাদানটি আপডেট করা হয় তখন আমি মানটি পরিবর্তন করে কিনা তা যাচাই করে দেখি:
@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>
}
}
আশা করি এটা সাহায্য করবে
withRouter
করছি তবে আমি ত্রুটি পাচ্ছি You should not use <Route> or withRouter() outside a <Router>
। <Router/>
উপরের কোডে আমি কোনও উপাদান দেখছি না । তাহলে এটি কীভাবে কাজ করছে?
<Switch>
উপাদানটি ডি-ফ্যাক্টো রাউটার হিসাবে কাজ করছে। <Route>
মিলে যাওয়ার পাথের জন্য কেবল প্রথম প্রবেশিকাটি রেন্ডার হবে। <Router/>
এই
উপরের প্রসারিত করতে, আপনাকে ইতিহাসের বিষয়টিতে যেতে হবে। আপনি যদি ব্যবহার করে থাকেন তবে ইতিহাসের অবজেক্টের বৈশিষ্ট্য এবং ফাংশনগুলিতে প্রপসের মাধ্যমে অ্যাক্সেস পাওয়ার জন্য আপনি উচ্চতর অর্ডার উপাদান (HoC) দিয়ে আপনার উপাদানটি BrowserRouter
আমদানি করতে withRouter
এবং মোড়ানো করতে পারেন।
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);
সচেতন হওয়ার একমাত্র বিষয় হ'ল রাউটার সহ এবং অন্যান্য উপায়গুলি অ্যাক্সেস করার জন্য প্রপসগুলিকে history
দূষিত করে মনে হয় কারণ তারা এতে বস্তুটিকে ডি-স্ট্রাকচার করে।
withRoutes
করুন withRouter
।
আপনার ইতিহাসের v4 লাইব ব্যবহার করা উচিত ।
সেখান থেকে উদাহরণ
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
ট্রিগার করে history.listen
। ইতিহাসের v4 ডক্সে একটি বেস URL ব্যবহারের উদাহরণটি দেখুন । যেহেতু এটি আসলে কোনও ব্রাউজারের নেটিভ অবজেক্টের একটি মোড়ক, এটি নেটিভের মতো ঠিক আচরণ করে না। history
history
const unlisten = history.listen(myListener); unlisten();
withRouter
,, history.listen
এবং useEffect
(প্রতিক্রিয়া হুকস) একসাথে বেশ সুন্দরভাবে কাজ করে:
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)
শ্রোতাদের কলব্যাক যে কোনও সময় কোনও রুট পরিবর্তিত হওয়ার পরে গুলি চালানো হবে, এবং এর জন্য ফিরে আসা history.listen
একটি শাটডাউন হ্যান্ডলার যা সুন্দরভাবে খেলবে useEffect
।
v5.1 দরকারী হুক পরিচয় করিয়ে দেয় 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
। আপনাকে নিশ্চিত করতে হবে যে ইউজলোকেশন () কলটি রাউটারটিকে গাছের মধ্যে রাখে একই উপাদানটিতে নেই: এখানে দেখুন
হুক সহ:
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>
উপাদান হিসাবে আমদানি এবং রেন্ডার
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]);
}
হুকস সহ
import { useHistory } from 'react-router-dom';
const Scroll = () => {
const history = useHistory();
useEffect(() => {
window.scrollTo(0, 0);
}, [history.location.pathname]);
return null;
}
প্রতিক্রিয়া হুক্স সহ, আমি ব্যবহার করছি 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])
কিছু ক্ষেত্রে আপনি এর render
পরিবর্তে এ্যাট্রিবিউট ব্যবহার করতে পারেন 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
পদ্ধতিতে রাষ্ট্র পরিবর্তন করেন তবে এর ফলে 'সর্বোচ্চ আপডেটের গভীরতা অতিক্রম' হতে পারে।
useEffect
হুক দিয়ে শ্রোতা যুক্ত না করেই রুটের পরিবর্তনগুলি সনাক্ত করা সম্ভব।
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);
আমি কেবল এই সমস্যার সাথে মোকাবিলা করেছি, তাই আমি প্রদত্ত অন্যান্য উত্তরের পরিপূরক হিসাবে আমার সমাধান যুক্ত করব।
এখানে সমস্যাটি হ'ল এটি useEffect
আপনি যেমনটি চান ঠিক তেমন কাজ করে না, যেহেতু কলটি কেবল প্রথম রেন্ডারের পরে ট্রিগার হয়ে যায় তাই অযাচিত দেরি হয়।
আপনি যদি রিডেক্সের মতো কিছু রাজ্য ব্যবস্থাপক ব্যবহার করেন, সম্ভাবনা হ'ল স্টোরটিতে দীর্ঘকালীন অবস্থার কারণে আপনি পর্দায় একটি ফ্লিকার পাবেন।
আপনি সত্যিই যা চান তা হ'ল useLayoutEffect
যেহেতু এটি তাত্ক্ষণিকভাবে ট্রিগার হয়ে যায়।
সুতরাং আমি একটি ছোট ইউটিলিটি ফাংশন লিখেছি যা আমি আমার রাউটারের মতো একই ডিরেক্টরিতে রেখেছি:
export const callApis = (fn, path) => {
useLayoutEffect(() => {
fn();
}, [path]);
};
যা আমি উপাদান এইচওসি এর মধ্যে থেকে এইভাবে কল করি:
callApis(() => getTopicById({topicId}), path);
path
ঠেকনা পাস পরার যে match
বস্তু ব্যবহার করে যখন withRouter
।
আমি ইতিহাসের পক্ষে ম্যানুয়ালি শোনার / প্রকাশ না করার পক্ষে নই। এটা ঠিক ইমো।