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:



enter image description here



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} &ndash;{" "}
{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.










share|improve this question
























  • 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










  • 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















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:



enter image description here



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} &ndash;{" "}
{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.










share|improve this question
























  • 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










  • 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













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:



enter image description here



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} &ndash;{" "}
{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.










share|improve this question















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:



enter image description here



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} &ndash;{" "}
{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






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited 2 days ago

























asked Nov 19 at 14:06









Hai Tien

77241330




77241330












  • 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










  • 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


















  • 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










  • 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
















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












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





  1. 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/>} />} />



  2. 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]
    });
    });
    }
    }







share|improve this answer























  • 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 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




    @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











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














 

draft saved


draft discarded


















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

























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





  1. 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/>} />} />



  2. 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]
    });
    });
    }
    }







share|improve this answer























  • 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 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




    @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















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





  1. 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/>} />} />



  2. 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]
    });
    });
    }
    }







share|improve this answer























  • 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 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




    @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













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





  1. 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/>} />} />



  2. 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]
    });
    });
    }
    }







share|improve this answer














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





  1. 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/>} />} />



  2. 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]
    });
    });
    }
    }








share|improve this answer














share|improve this answer



share|improve this answer








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 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




    @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






  • 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








  • 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


















 

draft saved


draft discarded



















































 


draft saved


draft discarded














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





















































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







Popular posts from this blog

404 Error Contact Form 7 ajax form submitting

How to know if a Active Directory user can login interactively

Refactoring coordinates for Minecraft Pi buildings written in Python