admin管理员组文章数量:1420187
So I'm stuck in a problem where when clicking on the Link the URL is changing but the view remains the same until I refresh the page.
I have looked into many solutions and the only thing working is to forcefully reload the page which I don't want as React is a SPA(Single Page Application). I have tried history.push() and Link both but the output remains the same. This is my repo if you need to look at other files.
App.js
import React from 'react';
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
import Header from './ponents/header/headerponent';
import HomePage from './pages/homepage/homepageponent';
import Details from './pages/detail/detailponent';
import './App.scss';
const App = () => (
<Router>
<Header />
<Switch>
<Route exact path="/" ponent={HomePage} />
<Route path="/:name" ponent={Details}/>
</Switch>
</Router>
);
Detail Component
import React from 'react';
import LinkButton from '../../ponents/link-button/link-buttonponent';
import './detail.style.scss';
class Details extends React.Component {
constructor(props) {
super(props);
this.state = {
borders: [],
country: '',
};
}
async ponentDidMount() {
const { name } = this.props.match.params;
fetch(`/${name}?fullText=true`)
.then((res) => res.json())
.then((data) => {
this.setState({ country: data[0] });
return data[0].borders;
})
.then((country) => {
for (let i = 0; i < country.length; i++) {
if (i > 2) break;
fetch(`/${country[i]}`)
.then((res) => res.json())
.then((data) =>
this.setState({ borders: [...this.state.borders, data.name] })
);
}
});
}
render() {
const { country, borders } = this.state;
if (country !== '') {
return (
<div className="detail-container">
<div className="detail-back-btn">
<LinkButton value="/">
<i className="fas fa-long-arrow-alt-left icon"></i> Back
</LinkButton>
</div>
<div className="detail-stats">
<img className="detail-flag" alt="Flag" src={country.flag} />
<div className="detail-text-container">
<h1 className="heading">{country.name}</h1>
<div className="detail-text">
<div className="left">
<p className="text">
Native Name: <span>{country.nativeName}</span>
</p>
<p className="text">
Population:
<span>{country.population.toLocaleString()}</span>
</p>
<p className="text">
Region: <span>{country.region}</span>
</p>
<p className="text">
Sub Region: <span>{country.subregion}</span>
</p>
<p className="text">
Capital: <span>{country.capital}</span>
</p>
</div>
<div className="right">
<p className="text">
Top Level Domain: <span>{country.topLevelDomain}</span>
</p>
<p className="text">
Currencies:{' '}
<span>
{country.currencies.map((e) => e.name).join(', ')}
</span>
</p>
<p className="text">
Languages:{' '}
<span>
{country.languages.map((e) => e.name).join(', ')}
</span>
</p>
</div>
</div>
<div className="border">
<p className="border-text">Border Countries:</p>
<span className="border-btn">
{borders.map((border, index) => (
<LinkButton key={index} value={border}>
{border}
</LinkButton>
))}
</span>
</div>
</div>
</div>
</div>
);
} else return null;
}
}
export default Details;
LinkButton Component
import React from 'react';
import { Link, withRouter } from 'react-router-dom';
import './link-button.style.scss';
//this is the brute force reload solution
//which is working, but i need a better approach
function refreshPage() {
setTimeout(() => {
window.location.reload(false);
}, 0);
console.log('page to reload');
}
const LinkButton = ({ value, children, history, match, location }) => {
console.log(history, match, location);
return (
<Link to={value} onClick={refreshPage}>
<button
className="link-btn"
value={value}
>
{children}
</button>
</Link>
);
};
export default withRouter(LinkButton);
So I'm stuck in a problem where when clicking on the Link the URL is changing but the view remains the same until I refresh the page.
I have looked into many solutions and the only thing working is to forcefully reload the page which I don't want as React is a SPA(Single Page Application). I have tried history.push() and Link both but the output remains the same. This is my repo if you need to look at other files.
App.js
import React from 'react';
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
import Header from './ponents/header/header.ponent';
import HomePage from './pages/homepage/homepage.ponent';
import Details from './pages/detail/detail.ponent';
import './App.scss';
const App = () => (
<Router>
<Header />
<Switch>
<Route exact path="/" ponent={HomePage} />
<Route path="/:name" ponent={Details}/>
</Switch>
</Router>
);
Detail Component
import React from 'react';
import LinkButton from '../../ponents/link-button/link-button.ponent';
import './detail.style.scss';
class Details extends React.Component {
constructor(props) {
super(props);
this.state = {
borders: [],
country: '',
};
}
async ponentDidMount() {
const { name } = this.props.match.params;
fetch(`https://restcountries.eu/rest/v2/name/${name}?fullText=true`)
.then((res) => res.json())
.then((data) => {
this.setState({ country: data[0] });
return data[0].borders;
})
.then((country) => {
for (let i = 0; i < country.length; i++) {
if (i > 2) break;
fetch(`https://restcountries.eu/rest/v2/alpha/${country[i]}`)
.then((res) => res.json())
.then((data) =>
this.setState({ borders: [...this.state.borders, data.name] })
);
}
});
}
render() {
const { country, borders } = this.state;
if (country !== '') {
return (
<div className="detail-container">
<div className="detail-back-btn">
<LinkButton value="/">
<i className="fas fa-long-arrow-alt-left icon"></i> Back
</LinkButton>
</div>
<div className="detail-stats">
<img className="detail-flag" alt="Flag" src={country.flag} />
<div className="detail-text-container">
<h1 className="heading">{country.name}</h1>
<div className="detail-text">
<div className="left">
<p className="text">
Native Name: <span>{country.nativeName}</span>
</p>
<p className="text">
Population:
<span>{country.population.toLocaleString()}</span>
</p>
<p className="text">
Region: <span>{country.region}</span>
</p>
<p className="text">
Sub Region: <span>{country.subregion}</span>
</p>
<p className="text">
Capital: <span>{country.capital}</span>
</p>
</div>
<div className="right">
<p className="text">
Top Level Domain: <span>{country.topLevelDomain}</span>
</p>
<p className="text">
Currencies:{' '}
<span>
{country.currencies.map((e) => e.name).join(', ')}
</span>
</p>
<p className="text">
Languages:{' '}
<span>
{country.languages.map((e) => e.name).join(', ')}
</span>
</p>
</div>
</div>
<div className="border">
<p className="border-text">Border Countries:</p>
<span className="border-btn">
{borders.map((border, index) => (
<LinkButton key={index} value={border}>
{border}
</LinkButton>
))}
</span>
</div>
</div>
</div>
</div>
);
} else return null;
}
}
export default Details;
LinkButton Component
import React from 'react';
import { Link, withRouter } from 'react-router-dom';
import './link-button.style.scss';
//this is the brute force reload solution
//which is working, but i need a better approach
function refreshPage() {
setTimeout(() => {
window.location.reload(false);
}, 0);
console.log('page to reload');
}
const LinkButton = ({ value, children, history, match, location }) => {
console.log(history, match, location);
return (
<Link to={value} onClick={refreshPage}>
<button
className="link-btn"
value={value}
>
{children}
</button>
</Link>
);
};
export default withRouter(LinkButton);
Share
Improve this question
edited Jun 14, 2021 at 17:04
Brian Thompson
14.4k4 gold badges27 silver badges49 bronze badges
asked Jun 14, 2021 at 16:50
Aman GuptaAman Gupta
33 bronze badges
1 Answer
Reset to default 9What you're seeing is a change from one URL to another, but they both match the same Route
path so react-router
will not re-mount the ponent. This is intentional, and also makes sense if you think about the purpose of the Switch
ponent.
For example: "/a" and "/b" both match <Route path="/:name" ponent={Details}/>
. So when changing from one to another, there's no reason for react-router
to re-mount the Details
ponent because it still matches.
To acplish what you are trying to do, you will need to listen to updates in the route parameter (the name
prop).
One strategy for this is to use the ponentDidUpdate
lifecycle method to check if the value has changed:
ponentDidUpdate(prevProps) {
if (this.props.match.params.name !== prevProps.match.params.name) {
// Refetch your data here because the "name" has changed.
}
}
Note that ponentDidUpdate
is not called on the initial render so you will need both lifecycle methods. However, you could pull out your fetch
call into it's own method so that both your ponentDidMount
and ponentDidUpdate
can reuse the same code.
For those using functional ponents with hooks, this listening process bees a little easier. Using a useEffect
hook with the route parameter as the dependency will acplish the same thing as both lifecycle methods in the class version.
const { name } = useParams();
useEffect(() => {
// Fetch data
}, [name]);
本文标签: javascriptReact Router Link is changing URL but the component remains sameStack Overflow
版权声明:本文标题:javascript - React Router Link is changing URL but the component remains same - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1745325788a2653585.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论