React router not rendered with second click
up vote
1
down vote
favorite
I use Router like the code below to switch between components includes Home, Sidebar, Detail, Category.
For the first load, It will display all recent posts, featured posts.
When I click a post to go detail It work well.
In detail page, I click to render new post but It does not render.
My code:
class App extends React.Component {
render () {
// if ('serviceWorker' in navigator) {
// const registration = runtime.register();
// }
module.hot.accept();
$("body").removeClass();
$("body").addClass("homepage");
<Helmet>
<title>{blog_title}</title>
<meta name="description" content={blog_description} />
</Helmet>
const {feature, main, sidebar, mainbottom, header } = this.props;
return (
<div id="all">
{header}
<div className="container">
<div className="main-feature" id="main-feature">
{feature}
</div>
</div>
<div id="content" className="site-content">
<div className="container">
<div className="divcontainer">
<div id="po-homepage" className="content-area">
{main}
</div>
<aside id="secondary" className="sidebar widget-area">
<div className="popular_post" id="popular_post">
{sidebar}
</div>
</aside>
</div>
</div>
</div>
<div className="cat-list">
<div className="container">
<div className="thecategories" id="thecategories">
{mainbottom}
</div>
</div>
</div>
</div>
)
}
}
Please see photo:
My detail post:
import React, {Component} from "react"; //nếu chỉ import React thì sẽ cần React.Component
import $ from 'jquery';
import { Helmet } from "react-helmet";
import {
BrowserRouter as Router,
Route,
Switch
} from 'react-router-dom';
class Detail extends React.Component {
constructor(props) {
super(props);
this.state = {
post: {}
};
}
componentDidMount() {
//scroll to detail
$(document).ready(function(){
$("html, body").animate({ scrollTop: $("#content").offset().top - 100 }, 500);
$("body").removeClass();
$("body").addClass("detailpage");
});
console.log(this.props.detailink);
var that = this;
var url = window.location.href.split("/");
var slug = url.pop() || url.pop();
// console.log(CelestialSettings.URL.api + "/posts?slug=" + slug);
fetch(CelestialSettings.URL.api + "/posts?slug=" + slug)
.then(function(response) {
if (!response.ok) {
throw Error(response.statusText);
}
return response.json();
})
.then(function(res) {
that.setState({ post: res[0] });
});
}
renderPosts() {
return (
<div className="card">
<div className="card-body">
<Helmet>
<title>{this.state.post.title.rendered}</title>
<meta name="description" content={this.state.post.excerpt.rendered.replace(/</?[^>]+(>|$)/g, "")} />
</Helmet>
<h1 className="card-title">{this.state.post.title.rendered}</h1>
<p className="card-text">
<small className="text-muted">
{this.state.post.author_name} –{" "}
{this.state.post.published_date}
</small>
</p>
{this.state.post.featured_image_src ? (
<img
className="featured-image"
src={this.state.post.featured_image_src}
alt="featured image"
/>
) : null}
<p
className="card-text"
dangerouslySetInnerHTML={{
__html: this.state.post.content.rendered
}}
/>
</div>
</div>
);
}
renderEmpty() {
return (
<div></div>
);
}
render() {
var href = window.location.href+"/?view=react";
return (
<div className="container post-entry">
{this.state.post.title ? this.renderPosts() : this.renderEmpty()}
</div>
);
}
}
export default Detail;
As I added ComponentDidUpdate(), it works but it renders loop back top first detail before render new post. I use like this.
componentDidUpdate() {
var that = this;
var url = window.location.href.split("/");
var slug = url.pop() || url.pop();
console.log(CelestialSettings.URL.api + "/posts?slug=" + slug);
fetch(CelestialSettings.URL.api + "/posts?slug=" + slug)
.then(function(response) {
if (!response.ok) {
throw Error(response.statusText);
}
return response.json();
})
.then(function(res) {
that.setState({ post: res[0] });
});
}
Any suggestion for my issue? Thank you so much.
reactjs
|
show 6 more comments
up vote
1
down vote
favorite
I use Router like the code below to switch between components includes Home, Sidebar, Detail, Category.
For the first load, It will display all recent posts, featured posts.
When I click a post to go detail It work well.
In detail page, I click to render new post but It does not render.
My code:
class App extends React.Component {
render () {
// if ('serviceWorker' in navigator) {
// const registration = runtime.register();
// }
module.hot.accept();
$("body").removeClass();
$("body").addClass("homepage");
<Helmet>
<title>{blog_title}</title>
<meta name="description" content={blog_description} />
</Helmet>
const {feature, main, sidebar, mainbottom, header } = this.props;
return (
<div id="all">
{header}
<div className="container">
<div className="main-feature" id="main-feature">
{feature}
</div>
</div>
<div id="content" className="site-content">
<div className="container">
<div className="divcontainer">
<div id="po-homepage" className="content-area">
{main}
</div>
<aside id="secondary" className="sidebar widget-area">
<div className="popular_post" id="popular_post">
{sidebar}
</div>
</aside>
</div>
</div>
</div>
<div className="cat-list">
<div className="container">
<div className="thecategories" id="thecategories">
{mainbottom}
</div>
</div>
</div>
</div>
)
}
}
Please see photo:
My detail post:
import React, {Component} from "react"; //nếu chỉ import React thì sẽ cần React.Component
import $ from 'jquery';
import { Helmet } from "react-helmet";
import {
BrowserRouter as Router,
Route,
Switch
} from 'react-router-dom';
class Detail extends React.Component {
constructor(props) {
super(props);
this.state = {
post: {}
};
}
componentDidMount() {
//scroll to detail
$(document).ready(function(){
$("html, body").animate({ scrollTop: $("#content").offset().top - 100 }, 500);
$("body").removeClass();
$("body").addClass("detailpage");
});
console.log(this.props.detailink);
var that = this;
var url = window.location.href.split("/");
var slug = url.pop() || url.pop();
// console.log(CelestialSettings.URL.api + "/posts?slug=" + slug);
fetch(CelestialSettings.URL.api + "/posts?slug=" + slug)
.then(function(response) {
if (!response.ok) {
throw Error(response.statusText);
}
return response.json();
})
.then(function(res) {
that.setState({ post: res[0] });
});
}
renderPosts() {
return (
<div className="card">
<div className="card-body">
<Helmet>
<title>{this.state.post.title.rendered}</title>
<meta name="description" content={this.state.post.excerpt.rendered.replace(/</?[^>]+(>|$)/g, "")} />
</Helmet>
<h1 className="card-title">{this.state.post.title.rendered}</h1>
<p className="card-text">
<small className="text-muted">
{this.state.post.author_name} –{" "}
{this.state.post.published_date}
</small>
</p>
{this.state.post.featured_image_src ? (
<img
className="featured-image"
src={this.state.post.featured_image_src}
alt="featured image"
/>
) : null}
<p
className="card-text"
dangerouslySetInnerHTML={{
__html: this.state.post.content.rendered
}}
/>
</div>
</div>
);
}
renderEmpty() {
return (
<div></div>
);
}
render() {
var href = window.location.href+"/?view=react";
return (
<div className="container post-entry">
{this.state.post.title ? this.renderPosts() : this.renderEmpty()}
</div>
);
}
}
export default Detail;
As I added ComponentDidUpdate(), it works but it renders loop back top first detail before render new post. I use like this.
componentDidUpdate() {
var that = this;
var url = window.location.href.split("/");
var slug = url.pop() || url.pop();
console.log(CelestialSettings.URL.api + "/posts?slug=" + slug);
fetch(CelestialSettings.URL.api + "/posts?slug=" + slug)
.then(function(response) {
if (!response.ok) {
throw Error(response.statusText);
}
return response.json();
})
.then(function(res) {
that.setState({ post: res[0] });
});
}
Any suggestion for my issue? Thank you so much.
reactjs
is your<Detail>
component exported withwithRouter
– Gabriele Petrioli
Nov 19 at 14:11
@GabrielePetrioli I do not know it. Can you explain me?
– Hai Tien
Nov 19 at 14:11
Please show the code with yourDetail
component.
– Gabriele Petrioli
Nov 19 at 14:17
@GabrielePetrioli Thank you so much. I updated detail component
– Hai Tien
Nov 19 at 14:18
Added answer with a solution.
– Gabriele Petrioli
Nov 19 at 14:23
|
show 6 more comments
up vote
1
down vote
favorite
up vote
1
down vote
favorite
I use Router like the code below to switch between components includes Home, Sidebar, Detail, Category.
For the first load, It will display all recent posts, featured posts.
When I click a post to go detail It work well.
In detail page, I click to render new post but It does not render.
My code:
class App extends React.Component {
render () {
// if ('serviceWorker' in navigator) {
// const registration = runtime.register();
// }
module.hot.accept();
$("body").removeClass();
$("body").addClass("homepage");
<Helmet>
<title>{blog_title}</title>
<meta name="description" content={blog_description} />
</Helmet>
const {feature, main, sidebar, mainbottom, header } = this.props;
return (
<div id="all">
{header}
<div className="container">
<div className="main-feature" id="main-feature">
{feature}
</div>
</div>
<div id="content" className="site-content">
<div className="container">
<div className="divcontainer">
<div id="po-homepage" className="content-area">
{main}
</div>
<aside id="secondary" className="sidebar widget-area">
<div className="popular_post" id="popular_post">
{sidebar}
</div>
</aside>
</div>
</div>
</div>
<div className="cat-list">
<div className="container">
<div className="thecategories" id="thecategories">
{mainbottom}
</div>
</div>
</div>
</div>
)
}
}
Please see photo:
My detail post:
import React, {Component} from "react"; //nếu chỉ import React thì sẽ cần React.Component
import $ from 'jquery';
import { Helmet } from "react-helmet";
import {
BrowserRouter as Router,
Route,
Switch
} from 'react-router-dom';
class Detail extends React.Component {
constructor(props) {
super(props);
this.state = {
post: {}
};
}
componentDidMount() {
//scroll to detail
$(document).ready(function(){
$("html, body").animate({ scrollTop: $("#content").offset().top - 100 }, 500);
$("body").removeClass();
$("body").addClass("detailpage");
});
console.log(this.props.detailink);
var that = this;
var url = window.location.href.split("/");
var slug = url.pop() || url.pop();
// console.log(CelestialSettings.URL.api + "/posts?slug=" + slug);
fetch(CelestialSettings.URL.api + "/posts?slug=" + slug)
.then(function(response) {
if (!response.ok) {
throw Error(response.statusText);
}
return response.json();
})
.then(function(res) {
that.setState({ post: res[0] });
});
}
renderPosts() {
return (
<div className="card">
<div className="card-body">
<Helmet>
<title>{this.state.post.title.rendered}</title>
<meta name="description" content={this.state.post.excerpt.rendered.replace(/</?[^>]+(>|$)/g, "")} />
</Helmet>
<h1 className="card-title">{this.state.post.title.rendered}</h1>
<p className="card-text">
<small className="text-muted">
{this.state.post.author_name} –{" "}
{this.state.post.published_date}
</small>
</p>
{this.state.post.featured_image_src ? (
<img
className="featured-image"
src={this.state.post.featured_image_src}
alt="featured image"
/>
) : null}
<p
className="card-text"
dangerouslySetInnerHTML={{
__html: this.state.post.content.rendered
}}
/>
</div>
</div>
);
}
renderEmpty() {
return (
<div></div>
);
}
render() {
var href = window.location.href+"/?view=react";
return (
<div className="container post-entry">
{this.state.post.title ? this.renderPosts() : this.renderEmpty()}
</div>
);
}
}
export default Detail;
As I added ComponentDidUpdate(), it works but it renders loop back top first detail before render new post. I use like this.
componentDidUpdate() {
var that = this;
var url = window.location.href.split("/");
var slug = url.pop() || url.pop();
console.log(CelestialSettings.URL.api + "/posts?slug=" + slug);
fetch(CelestialSettings.URL.api + "/posts?slug=" + slug)
.then(function(response) {
if (!response.ok) {
throw Error(response.statusText);
}
return response.json();
})
.then(function(res) {
that.setState({ post: res[0] });
});
}
Any suggestion for my issue? Thank you so much.
reactjs
I use Router like the code below to switch between components includes Home, Sidebar, Detail, Category.
For the first load, It will display all recent posts, featured posts.
When I click a post to go detail It work well.
In detail page, I click to render new post but It does not render.
My code:
class App extends React.Component {
render () {
// if ('serviceWorker' in navigator) {
// const registration = runtime.register();
// }
module.hot.accept();
$("body").removeClass();
$("body").addClass("homepage");
<Helmet>
<title>{blog_title}</title>
<meta name="description" content={blog_description} />
</Helmet>
const {feature, main, sidebar, mainbottom, header } = this.props;
return (
<div id="all">
{header}
<div className="container">
<div className="main-feature" id="main-feature">
{feature}
</div>
</div>
<div id="content" className="site-content">
<div className="container">
<div className="divcontainer">
<div id="po-homepage" className="content-area">
{main}
</div>
<aside id="secondary" className="sidebar widget-area">
<div className="popular_post" id="popular_post">
{sidebar}
</div>
</aside>
</div>
</div>
</div>
<div className="cat-list">
<div className="container">
<div className="thecategories" id="thecategories">
{mainbottom}
</div>
</div>
</div>
</div>
)
}
}
Please see photo:
My detail post:
import React, {Component} from "react"; //nếu chỉ import React thì sẽ cần React.Component
import $ from 'jquery';
import { Helmet } from "react-helmet";
import {
BrowserRouter as Router,
Route,
Switch
} from 'react-router-dom';
class Detail extends React.Component {
constructor(props) {
super(props);
this.state = {
post: {}
};
}
componentDidMount() {
//scroll to detail
$(document).ready(function(){
$("html, body").animate({ scrollTop: $("#content").offset().top - 100 }, 500);
$("body").removeClass();
$("body").addClass("detailpage");
});
console.log(this.props.detailink);
var that = this;
var url = window.location.href.split("/");
var slug = url.pop() || url.pop();
// console.log(CelestialSettings.URL.api + "/posts?slug=" + slug);
fetch(CelestialSettings.URL.api + "/posts?slug=" + slug)
.then(function(response) {
if (!response.ok) {
throw Error(response.statusText);
}
return response.json();
})
.then(function(res) {
that.setState({ post: res[0] });
});
}
renderPosts() {
return (
<div className="card">
<div className="card-body">
<Helmet>
<title>{this.state.post.title.rendered}</title>
<meta name="description" content={this.state.post.excerpt.rendered.replace(/</?[^>]+(>|$)/g, "")} />
</Helmet>
<h1 className="card-title">{this.state.post.title.rendered}</h1>
<p className="card-text">
<small className="text-muted">
{this.state.post.author_name} –{" "}
{this.state.post.published_date}
</small>
</p>
{this.state.post.featured_image_src ? (
<img
className="featured-image"
src={this.state.post.featured_image_src}
alt="featured image"
/>
) : null}
<p
className="card-text"
dangerouslySetInnerHTML={{
__html: this.state.post.content.rendered
}}
/>
</div>
</div>
);
}
renderEmpty() {
return (
<div></div>
);
}
render() {
var href = window.location.href+"/?view=react";
return (
<div className="container post-entry">
{this.state.post.title ? this.renderPosts() : this.renderEmpty()}
</div>
);
}
}
export default Detail;
As I added ComponentDidUpdate(), it works but it renders loop back top first detail before render new post. I use like this.
componentDidUpdate() {
var that = this;
var url = window.location.href.split("/");
var slug = url.pop() || url.pop();
console.log(CelestialSettings.URL.api + "/posts?slug=" + slug);
fetch(CelestialSettings.URL.api + "/posts?slug=" + slug)
.then(function(response) {
if (!response.ok) {
throw Error(response.statusText);
}
return response.json();
})
.then(function(res) {
that.setState({ post: res[0] });
});
}
Any suggestion for my issue? Thank you so much.
reactjs
reactjs
edited 2 days ago
asked Nov 19 at 14:06
Hai Tien
77241330
77241330
is your<Detail>
component exported withwithRouter
– Gabriele Petrioli
Nov 19 at 14:11
@GabrielePetrioli I do not know it. Can you explain me?
– Hai Tien
Nov 19 at 14:11
Please show the code with yourDetail
component.
– Gabriele Petrioli
Nov 19 at 14:17
@GabrielePetrioli Thank you so much. I updated detail component
– Hai Tien
Nov 19 at 14:18
Added answer with a solution.
– Gabriele Petrioli
Nov 19 at 14:23
|
show 6 more comments
is your<Detail>
component exported withwithRouter
– Gabriele Petrioli
Nov 19 at 14:11
@GabrielePetrioli I do not know it. Can you explain me?
– Hai Tien
Nov 19 at 14:11
Please show the code with yourDetail
component.
– Gabriele Petrioli
Nov 19 at 14:17
@GabrielePetrioli Thank you so much. I updated detail component
– Hai Tien
Nov 19 at 14:18
Added answer with a solution.
– Gabriele Petrioli
Nov 19 at 14:23
is your
<Detail>
component exported with withRouter
– Gabriele Petrioli
Nov 19 at 14:11
is your
<Detail>
component exported with withRouter
– Gabriele Petrioli
Nov 19 at 14:11
@GabrielePetrioli I do not know it. Can you explain me?
– Hai Tien
Nov 19 at 14:11
@GabrielePetrioli I do not know it. Can you explain me?
– Hai Tien
Nov 19 at 14:11
Please show the code with your
Detail
component.– Gabriele Petrioli
Nov 19 at 14:17
Please show the code with your
Detail
component.– Gabriele Petrioli
Nov 19 at 14:17
@GabrielePetrioli Thank you so much. I updated detail component
– Hai Tien
Nov 19 at 14:18
@GabrielePetrioli Thank you so much. I updated detail component
– Hai Tien
Nov 19 at 14:18
Added answer with a solution.
– Gabriele Petrioli
Nov 19 at 14:23
Added answer with a solution.
– Gabriele Petrioli
Nov 19 at 14:23
|
show 6 more comments
1 Answer
1
active
oldest
votes
up vote
2
down vote
accepted
Your Detail
component needs to be aware that the url changed and since no relevant properties are passed when you try to render it you must use the withRouter
HOC provided by react router
so at the top of your Details component file
import {
BrowserRouter as Router,
Route,
Switch,
withRouter // add this (and the comma in the above line)
} from 'react-router-dom';
and at the bottom where you export
it use
export default withRouter(Detail);
Update
Reading your Details
code a bit more i see that you fetch
the content on the ComponentDidMount
lifecycle event, but when you load a new post you remain to the same page so the Details
component is not unmounted/remounted, it is just updated with new props and so the ComponentDidMount
does not fire again. You will have to also use ComponentDidUpdate
Some additional info
Since you are using the react-router you should not be parsing the
window.location.href
yourself trying to figure the slug. You can automatically pass it down from the props provided by the router.
<!-- language: lang-js -->
<Route
path={CelestialSettings.path + 'posts/:slug'}
render={(props) => <App header={<Header/>}
main={<Detail slug={props.match.slug} detailink={CelestialSettings.path + 'posts/:slug'} />}
sidebar={<Popular />}
feature={<Featurex/>}
mainbottom={<Categories/>} />} />
Then in your
ComponentDidUpdate
<!-- language: lang-js -->
componentDidUpdate(newProps) {
const {slug} = newProps;
const that = this; // you do not need this if you use arrow functions
if (slug !== this.props.slug) {
fetch(CelestialSettings.URL.api + "/posts?slug=" + slug)
.then(function(response) {
if (!response.ok) {
throw Error(response.statusText);
}
return response.json();
})
.then(function(res) {
that.setState({
post: res[0]
});
});
}
}
Thank you so much but it seems that it does not work. Do you know reason why?
– Hai Tien
Nov 19 at 14:32
2
@HaiTien i see. Reading yourDetails
code a bit more i see that you fetch the content on theComponentDidMount
, but when you change load a new post you remain to the same page so theDetails
component is not unmounted/remounted, it is just updated with new props so theComponentDidMount
does not fire again. You will have to also useComponentDidUpdate
.
– Gabriele Petrioli
Nov 19 at 15:03
1
@GabrielePetrioli Wouldn't that be info that should be part of the answer instead of as a comment? :)
– Icepickle
Nov 19 at 15:28
1
@HaiTien updated answer
– Gabriele Petrioli
Nov 19 at 16:11
1
@Icepickle fair point. Added it to updated answer
– Gabriele Petrioli
Nov 19 at 16:14
|
show 7 more comments
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
2
down vote
accepted
Your Detail
component needs to be aware that the url changed and since no relevant properties are passed when you try to render it you must use the withRouter
HOC provided by react router
so at the top of your Details component file
import {
BrowserRouter as Router,
Route,
Switch,
withRouter // add this (and the comma in the above line)
} from 'react-router-dom';
and at the bottom where you export
it use
export default withRouter(Detail);
Update
Reading your Details
code a bit more i see that you fetch
the content on the ComponentDidMount
lifecycle event, but when you load a new post you remain to the same page so the Details
component is not unmounted/remounted, it is just updated with new props and so the ComponentDidMount
does not fire again. You will have to also use ComponentDidUpdate
Some additional info
Since you are using the react-router you should not be parsing the
window.location.href
yourself trying to figure the slug. You can automatically pass it down from the props provided by the router.
<!-- language: lang-js -->
<Route
path={CelestialSettings.path + 'posts/:slug'}
render={(props) => <App header={<Header/>}
main={<Detail slug={props.match.slug} detailink={CelestialSettings.path + 'posts/:slug'} />}
sidebar={<Popular />}
feature={<Featurex/>}
mainbottom={<Categories/>} />} />
Then in your
ComponentDidUpdate
<!-- language: lang-js -->
componentDidUpdate(newProps) {
const {slug} = newProps;
const that = this; // you do not need this if you use arrow functions
if (slug !== this.props.slug) {
fetch(CelestialSettings.URL.api + "/posts?slug=" + slug)
.then(function(response) {
if (!response.ok) {
throw Error(response.statusText);
}
return response.json();
})
.then(function(res) {
that.setState({
post: res[0]
});
});
}
}
Thank you so much but it seems that it does not work. Do you know reason why?
– Hai Tien
Nov 19 at 14:32
2
@HaiTien i see. Reading yourDetails
code a bit more i see that you fetch the content on theComponentDidMount
, but when you change load a new post you remain to the same page so theDetails
component is not unmounted/remounted, it is just updated with new props so theComponentDidMount
does not fire again. You will have to also useComponentDidUpdate
.
– Gabriele Petrioli
Nov 19 at 15:03
1
@GabrielePetrioli Wouldn't that be info that should be part of the answer instead of as a comment? :)
– Icepickle
Nov 19 at 15:28
1
@HaiTien updated answer
– Gabriele Petrioli
Nov 19 at 16:11
1
@Icepickle fair point. Added it to updated answer
– Gabriele Petrioli
Nov 19 at 16:14
|
show 7 more comments
up vote
2
down vote
accepted
Your Detail
component needs to be aware that the url changed and since no relevant properties are passed when you try to render it you must use the withRouter
HOC provided by react router
so at the top of your Details component file
import {
BrowserRouter as Router,
Route,
Switch,
withRouter // add this (and the comma in the above line)
} from 'react-router-dom';
and at the bottom where you export
it use
export default withRouter(Detail);
Update
Reading your Details
code a bit more i see that you fetch
the content on the ComponentDidMount
lifecycle event, but when you load a new post you remain to the same page so the Details
component is not unmounted/remounted, it is just updated with new props and so the ComponentDidMount
does not fire again. You will have to also use ComponentDidUpdate
Some additional info
Since you are using the react-router you should not be parsing the
window.location.href
yourself trying to figure the slug. You can automatically pass it down from the props provided by the router.
<!-- language: lang-js -->
<Route
path={CelestialSettings.path + 'posts/:slug'}
render={(props) => <App header={<Header/>}
main={<Detail slug={props.match.slug} detailink={CelestialSettings.path + 'posts/:slug'} />}
sidebar={<Popular />}
feature={<Featurex/>}
mainbottom={<Categories/>} />} />
Then in your
ComponentDidUpdate
<!-- language: lang-js -->
componentDidUpdate(newProps) {
const {slug} = newProps;
const that = this; // you do not need this if you use arrow functions
if (slug !== this.props.slug) {
fetch(CelestialSettings.URL.api + "/posts?slug=" + slug)
.then(function(response) {
if (!response.ok) {
throw Error(response.statusText);
}
return response.json();
})
.then(function(res) {
that.setState({
post: res[0]
});
});
}
}
Thank you so much but it seems that it does not work. Do you know reason why?
– Hai Tien
Nov 19 at 14:32
2
@HaiTien i see. Reading yourDetails
code a bit more i see that you fetch the content on theComponentDidMount
, but when you change load a new post you remain to the same page so theDetails
component is not unmounted/remounted, it is just updated with new props so theComponentDidMount
does not fire again. You will have to also useComponentDidUpdate
.
– Gabriele Petrioli
Nov 19 at 15:03
1
@GabrielePetrioli Wouldn't that be info that should be part of the answer instead of as a comment? :)
– Icepickle
Nov 19 at 15:28
1
@HaiTien updated answer
– Gabriele Petrioli
Nov 19 at 16:11
1
@Icepickle fair point. Added it to updated answer
– Gabriele Petrioli
Nov 19 at 16:14
|
show 7 more comments
up vote
2
down vote
accepted
up vote
2
down vote
accepted
Your Detail
component needs to be aware that the url changed and since no relevant properties are passed when you try to render it you must use the withRouter
HOC provided by react router
so at the top of your Details component file
import {
BrowserRouter as Router,
Route,
Switch,
withRouter // add this (and the comma in the above line)
} from 'react-router-dom';
and at the bottom where you export
it use
export default withRouter(Detail);
Update
Reading your Details
code a bit more i see that you fetch
the content on the ComponentDidMount
lifecycle event, but when you load a new post you remain to the same page so the Details
component is not unmounted/remounted, it is just updated with new props and so the ComponentDidMount
does not fire again. You will have to also use ComponentDidUpdate
Some additional info
Since you are using the react-router you should not be parsing the
window.location.href
yourself trying to figure the slug. You can automatically pass it down from the props provided by the router.
<!-- language: lang-js -->
<Route
path={CelestialSettings.path + 'posts/:slug'}
render={(props) => <App header={<Header/>}
main={<Detail slug={props.match.slug} detailink={CelestialSettings.path + 'posts/:slug'} />}
sidebar={<Popular />}
feature={<Featurex/>}
mainbottom={<Categories/>} />} />
Then in your
ComponentDidUpdate
<!-- language: lang-js -->
componentDidUpdate(newProps) {
const {slug} = newProps;
const that = this; // you do not need this if you use arrow functions
if (slug !== this.props.slug) {
fetch(CelestialSettings.URL.api + "/posts?slug=" + slug)
.then(function(response) {
if (!response.ok) {
throw Error(response.statusText);
}
return response.json();
})
.then(function(res) {
that.setState({
post: res[0]
});
});
}
}
Your Detail
component needs to be aware that the url changed and since no relevant properties are passed when you try to render it you must use the withRouter
HOC provided by react router
so at the top of your Details component file
import {
BrowserRouter as Router,
Route,
Switch,
withRouter // add this (and the comma in the above line)
} from 'react-router-dom';
and at the bottom where you export
it use
export default withRouter(Detail);
Update
Reading your Details
code a bit more i see that you fetch
the content on the ComponentDidMount
lifecycle event, but when you load a new post you remain to the same page so the Details
component is not unmounted/remounted, it is just updated with new props and so the ComponentDidMount
does not fire again. You will have to also use ComponentDidUpdate
Some additional info
Since you are using the react-router you should not be parsing the
window.location.href
yourself trying to figure the slug. You can automatically pass it down from the props provided by the router.
<!-- language: lang-js -->
<Route
path={CelestialSettings.path + 'posts/:slug'}
render={(props) => <App header={<Header/>}
main={<Detail slug={props.match.slug} detailink={CelestialSettings.path + 'posts/:slug'} />}
sidebar={<Popular />}
feature={<Featurex/>}
mainbottom={<Categories/>} />} />
Then in your
ComponentDidUpdate
<!-- language: lang-js -->
componentDidUpdate(newProps) {
const {slug} = newProps;
const that = this; // you do not need this if you use arrow functions
if (slug !== this.props.slug) {
fetch(CelestialSettings.URL.api + "/posts?slug=" + slug)
.then(function(response) {
if (!response.ok) {
throw Error(response.statusText);
}
return response.json();
})
.then(function(res) {
that.setState({
post: res[0]
});
});
}
}
edited Nov 19 at 17:35
answered Nov 19 at 14:23
Gabriele Petrioli
147k22194249
147k22194249
Thank you so much but it seems that it does not work. Do you know reason why?
– Hai Tien
Nov 19 at 14:32
2
@HaiTien i see. Reading yourDetails
code a bit more i see that you fetch the content on theComponentDidMount
, but when you change load a new post you remain to the same page so theDetails
component is not unmounted/remounted, it is just updated with new props so theComponentDidMount
does not fire again. You will have to also useComponentDidUpdate
.
– Gabriele Petrioli
Nov 19 at 15:03
1
@GabrielePetrioli Wouldn't that be info that should be part of the answer instead of as a comment? :)
– Icepickle
Nov 19 at 15:28
1
@HaiTien updated answer
– Gabriele Petrioli
Nov 19 at 16:11
1
@Icepickle fair point. Added it to updated answer
– Gabriele Petrioli
Nov 19 at 16:14
|
show 7 more comments
Thank you so much but it seems that it does not work. Do you know reason why?
– Hai Tien
Nov 19 at 14:32
2
@HaiTien i see. Reading yourDetails
code a bit more i see that you fetch the content on theComponentDidMount
, but when you change load a new post you remain to the same page so theDetails
component is not unmounted/remounted, it is just updated with new props so theComponentDidMount
does not fire again. You will have to also useComponentDidUpdate
.
– Gabriele Petrioli
Nov 19 at 15:03
1
@GabrielePetrioli Wouldn't that be info that should be part of the answer instead of as a comment? :)
– Icepickle
Nov 19 at 15:28
1
@HaiTien updated answer
– Gabriele Petrioli
Nov 19 at 16:11
1
@Icepickle fair point. Added it to updated answer
– Gabriele Petrioli
Nov 19 at 16:14
Thank you so much but it seems that it does not work. Do you know reason why?
– Hai Tien
Nov 19 at 14:32
Thank you so much but it seems that it does not work. Do you know reason why?
– Hai Tien
Nov 19 at 14:32
2
2
@HaiTien i see. Reading your
Details
code a bit more i see that you fetch the content on the ComponentDidMount
, but when you change load a new post you remain to the same page so the Details
component is not unmounted/remounted, it is just updated with new props so the ComponentDidMount
does not fire again. You will have to also use ComponentDidUpdate
.– Gabriele Petrioli
Nov 19 at 15:03
@HaiTien i see. Reading your
Details
code a bit more i see that you fetch the content on the ComponentDidMount
, but when you change load a new post you remain to the same page so the Details
component is not unmounted/remounted, it is just updated with new props so the ComponentDidMount
does not fire again. You will have to also use ComponentDidUpdate
.– Gabriele Petrioli
Nov 19 at 15:03
1
1
@GabrielePetrioli Wouldn't that be info that should be part of the answer instead of as a comment? :)
– Icepickle
Nov 19 at 15:28
@GabrielePetrioli Wouldn't that be info that should be part of the answer instead of as a comment? :)
– Icepickle
Nov 19 at 15:28
1
1
@HaiTien updated answer
– Gabriele Petrioli
Nov 19 at 16:11
@HaiTien updated answer
– Gabriele Petrioli
Nov 19 at 16:11
1
1
@Icepickle fair point. Added it to updated answer
– Gabriele Petrioli
Nov 19 at 16:14
@Icepickle fair point. Added it to updated answer
– Gabriele Petrioli
Nov 19 at 16:14
|
show 7 more comments
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53376384%2freact-router-not-rendered-with-second-click%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
is your
<Detail>
component exported withwithRouter
– Gabriele Petrioli
Nov 19 at 14:11
@GabrielePetrioli I do not know it. Can you explain me?
– Hai Tien
Nov 19 at 14:11
Please show the code with your
Detail
component.– Gabriele Petrioli
Nov 19 at 14:17
@GabrielePetrioli Thank you so much. I updated detail component
– Hai Tien
Nov 19 at 14:18
Added answer with a solution.
– Gabriele Petrioli
Nov 19 at 14:23