admin管理员组文章数量:1392110
I have a demo application that uses React (v.16.8.6) and HashRouter (a requirement to use hash router). My app simply fetches some weather data and displays the relevant ponents for weather in some cities.
The problem is that there is a search feature in index page and also similar feature on search page. When search term is given app redirects to #/search/{term}
route. Everything is working as expected however when I am already on search page and trigger new search I redirect to same search page with different {term}
slug (needed in order to update browser current url including hash).
As a result page is NOT reloaded and ponent is NOT remounted so lifecycle hooks (especially ponentDidMount
where the setup is made) are not triggered.
I made a workaround to simulate ponent re-load, but it is sort of a hack (eg manipulating state directly and settting timeout see below relevant code).
Is there a better way of achieving redirect to same page (and changing browser url including hash) while ponent is reloaded/remounted correctly?
App.js
import React, { Component } from 'react';
import { HashRouter, Route, Switch } from 'react-router-dom';
import HomePage from './home';
import SearchPage from './search';
import WeatherPage from './weather';
import './App.css';
class App extends Component {
render() {
return (
<HashRouter basename="/" hashType="slash">
<Switch>
<Route exact path={'/'} ponent={HomePage}></Route>
<Route path={'/weather/:woeid'} ponent={WeatherPage}></Route>
<Route path={'/search/:term'} ponent={SearchPage}></Route>
</Switch>
</HashRouter>
);
}
}
export default App;
SearchPage.js ponent
import React, { Component } from 'react';
import { Redirect } from 'react-router-dom';
import Weather from '../ponents/Weather';
function fetchData( term ) {
return fetch('{api_url_here}?keyword='+term)
.then(response => response.json());
}
class SearchPage extends Component {
constructor(props){
super(props);
this.state = {
loading: true,
text: this.props.match.params.term,
redirect: false,
data: null
};
}
ponentDidMount() {
fetchData(this.props.match.params.term).then(jsonResponse => {
this.setState({
loading: false,
data: jsonResponse
});
});
}
handleOnClick = () => {
this.setState({redirect: true});
}
handleInput = (evt) => {
this.setState({text: evt.target.value});
}
render() {
// any way to avoid this workaround while redirecting to same page?
// [from here]
if (this.state.redirect) {
this.state.redirect = false;
this.state.text = this.state.text.toLowerCase();
this.state.data = null;
this.state.loading = true;
// simulate ponentDidMount, since it os not re-called on same page
setTimeout(()=>(fetchData(this.state.text).then(jsonResponse => {
this.setState({
loading: false,
data: jsonResponse
});
})), 40);
// redirect and update url
return <Redirect to={"/search/"+this.state.text} />;
// [to here]
}
return (
<div>
<h1>Search Page</h1>
<div>
<input type="text" placeholder="search.." value={this.state.text} onChange={this.handleInput} />
<button type="button" onClick={this.handleOnClick}>Search!</button>
</div>
{this.state.loading ? 'Loading..' : (this.state.data && this.state.data.length ? this.state.data.map(res => (<Weather woeid={res.woeid} city={res.title} />)) : 'No results found!')}
</div>
);
}
}
export default SearchPage;
Solution based on Redirect (which will re-load / re-mount ponent) (Tholle's answer)
change App to following:
class App extends Component {
render() {
return (
<HashRouter basename="/" hashType="slash">
<Switch>
<Route exact path={'/'} ponent={HomePage}></Route>
<Route path={'/weather/:woeid'} ponent={WeatherPage}></Route>
<Route path={'/search/:term'} render={props => <SearchPage key={props.match.params.term.toLowerCase()} {...props} />}></Route>
</Switch>
</HashRouter>
);
}
}
change SearchPage to following:
class SearchPage extends Component {
constructor(props){
super(props);
this.state = {
loading: true,
text: this.props.match.params.term,
redirect: false,
data: null
};
}
ponentDidMount() {
fetchData(this.props.match.params.term).then(jsonResponse => {
this.setState({
loading: false,
data: jsonResponse
});
});
}
handleOnClick = () => {
this.setState({redirect: true});
}
handleInput = (evt) => {
this.setState({text: evt.target.value});
}
render() {
if (this.state.redirect) {
// redirect and update url
return <Redirect to={"/search/"+this.state.text.toLowerCase()} />;
}
return (
<div>
<h1>Search Page</h1>
<div>
<input type="text" placeholder="search.." value={this.state.text} onChange={this.handleInput} />
<button type="button" onClick={this.handleOnClick}>Search!</button>
</div>
{this.state.loading ? 'Loading..' : (this.state.data && this.state.data.length ? this.state.data.map(res => (<Weather woeid={res.woeid} city={res.title} />)) : 'No results found!')}
</div>
);
}
}
I have a demo application that uses React (v.16.8.6) and HashRouter (a requirement to use hash router). My app simply fetches some weather data and displays the relevant ponents for weather in some cities.
The problem is that there is a search feature in index page and also similar feature on search page. When search term is given app redirects to #/search/{term}
route. Everything is working as expected however when I am already on search page and trigger new search I redirect to same search page with different {term}
slug (needed in order to update browser current url including hash).
As a result page is NOT reloaded and ponent is NOT remounted so lifecycle hooks (especially ponentDidMount
where the setup is made) are not triggered.
I made a workaround to simulate ponent re-load, but it is sort of a hack (eg manipulating state directly and settting timeout see below relevant code).
Is there a better way of achieving redirect to same page (and changing browser url including hash) while ponent is reloaded/remounted correctly?
App.js
import React, { Component } from 'react';
import { HashRouter, Route, Switch } from 'react-router-dom';
import HomePage from './home';
import SearchPage from './search';
import WeatherPage from './weather';
import './App.css';
class App extends Component {
render() {
return (
<HashRouter basename="/" hashType="slash">
<Switch>
<Route exact path={'/'} ponent={HomePage}></Route>
<Route path={'/weather/:woeid'} ponent={WeatherPage}></Route>
<Route path={'/search/:term'} ponent={SearchPage}></Route>
</Switch>
</HashRouter>
);
}
}
export default App;
SearchPage.js ponent
import React, { Component } from 'react';
import { Redirect } from 'react-router-dom';
import Weather from '../ponents/Weather';
function fetchData( term ) {
return fetch('{api_url_here}?keyword='+term)
.then(response => response.json());
}
class SearchPage extends Component {
constructor(props){
super(props);
this.state = {
loading: true,
text: this.props.match.params.term,
redirect: false,
data: null
};
}
ponentDidMount() {
fetchData(this.props.match.params.term).then(jsonResponse => {
this.setState({
loading: false,
data: jsonResponse
});
});
}
handleOnClick = () => {
this.setState({redirect: true});
}
handleInput = (evt) => {
this.setState({text: evt.target.value});
}
render() {
// any way to avoid this workaround while redirecting to same page?
// [from here]
if (this.state.redirect) {
this.state.redirect = false;
this.state.text = this.state.text.toLowerCase();
this.state.data = null;
this.state.loading = true;
// simulate ponentDidMount, since it os not re-called on same page
setTimeout(()=>(fetchData(this.state.text).then(jsonResponse => {
this.setState({
loading: false,
data: jsonResponse
});
})), 40);
// redirect and update url
return <Redirect to={"/search/"+this.state.text} />;
// [to here]
}
return (
<div>
<h1>Search Page</h1>
<div>
<input type="text" placeholder="search.." value={this.state.text} onChange={this.handleInput} />
<button type="button" onClick={this.handleOnClick}>Search!</button>
</div>
{this.state.loading ? 'Loading..' : (this.state.data && this.state.data.length ? this.state.data.map(res => (<Weather woeid={res.woeid} city={res.title} />)) : 'No results found!')}
</div>
);
}
}
export default SearchPage;
Solution based on Redirect (which will re-load / re-mount ponent) (Tholle's answer)
change App to following:
class App extends Component {
render() {
return (
<HashRouter basename="/" hashType="slash">
<Switch>
<Route exact path={'/'} ponent={HomePage}></Route>
<Route path={'/weather/:woeid'} ponent={WeatherPage}></Route>
<Route path={'/search/:term'} render={props => <SearchPage key={props.match.params.term.toLowerCase()} {...props} />}></Route>
</Switch>
</HashRouter>
);
}
}
change SearchPage to following:
class SearchPage extends Component {
constructor(props){
super(props);
this.state = {
loading: true,
text: this.props.match.params.term,
redirect: false,
data: null
};
}
ponentDidMount() {
fetchData(this.props.match.params.term).then(jsonResponse => {
this.setState({
loading: false,
data: jsonResponse
});
});
}
handleOnClick = () => {
this.setState({redirect: true});
}
handleInput = (evt) => {
this.setState({text: evt.target.value});
}
render() {
if (this.state.redirect) {
// redirect and update url
return <Redirect to={"/search/"+this.state.text.toLowerCase()} />;
}
return (
<div>
<h1>Search Page</h1>
<div>
<input type="text" placeholder="search.." value={this.state.text} onChange={this.handleInput} />
<button type="button" onClick={this.handleOnClick}>Search!</button>
</div>
{this.state.loading ? 'Loading..' : (this.state.data && this.state.data.length ? this.state.data.map(res => (<Weather woeid={res.woeid} city={res.title} />)) : 'No results found!')}
</div>
);
}
}
Share
Improve this question
edited Apr 15, 2019 at 10:56
Nikos M.
asked Apr 15, 2019 at 9:54
Nikos M.Nikos M.
8,3554 gold badges40 silver badges45 bronze badges
2 Answers
Reset to default 1One way of going about it is to add a ponentDidUpdate
lifecycle hook to the SearchPage
ponent and check if the term
parameter changes and do the search again.
If you want to remount the ponent when the term
parameter changes instead, you can use the key
prop to unmount the previous ponent and mount a new one when the key
changes.
<Route
path={"/search/:term"}
render={props => <SearchPage key={props.match.params.term} {...props} />}
/>
Use the Link
from react-router-dom
instead of the <button>
to change the route instead of just redirecting. Then in the onClick of the <Link>
ponent call the fetchData
and set the state accordingly.
<Link className="btn" to={"/search/"+this.state.text} onClick={this.handleOnClick}>Search!</Link>
Then in the handleOnClick
function
handleOnClick() {
this.setState({
loading: true
});
fetchData(this.state.text).then(jsonResponse => {
this.setState({
loading: false,
data: jsonResponse
});
});
}
本文标签:
版权声明:本文标题:javascript - React Router trigger re-loadre-mount component on redirecting to same page with different slug - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744775317a2624587.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论