React router not rendered with second click
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
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 '18 at 14:11
@GabrielePetrioli I do not know it. Can you explain me?
– Hai Tien
Nov 19 '18 at 14:11
Please show the code with yourDetail
component.
– Gabriele Petrioli
Nov 19 '18 at 14:17
@GabrielePetrioli Thank you so much. I updated detail component
– Hai Tien
Nov 19 '18 at 14:18
Added answer with a solution.
– Gabriele Petrioli
Nov 19 '18 at 14:23
|
show 6 more comments
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 Nov 24 '18 at 4:33
Hai Tien
asked Nov 19 '18 at 14:06
Hai TienHai Tien
80041530
80041530
is your<Detail>
component exported withwithRouter
– Gabriele Petrioli
Nov 19 '18 at 14:11
@GabrielePetrioli I do not know it. Can you explain me?
– Hai Tien
Nov 19 '18 at 14:11
Please show the code with yourDetail
component.
– Gabriele Petrioli
Nov 19 '18 at 14:17
@GabrielePetrioli Thank you so much. I updated detail component
– Hai Tien
Nov 19 '18 at 14:18
Added answer with a solution.
– Gabriele Petrioli
Nov 19 '18 at 14:23
|
show 6 more comments
is your<Detail>
component exported withwithRouter
– Gabriele Petrioli
Nov 19 '18 at 14:11
@GabrielePetrioli I do not know it. Can you explain me?
– Hai Tien
Nov 19 '18 at 14:11
Please show the code with yourDetail
component.
– Gabriele Petrioli
Nov 19 '18 at 14:17
@GabrielePetrioli Thank you so much. I updated detail component
– Hai Tien
Nov 19 '18 at 14:18
Added answer with a solution.
– Gabriele Petrioli
Nov 19 '18 at 14:23
is your
<Detail>
component exported with withRouter
– Gabriele Petrioli
Nov 19 '18 at 14:11
is your
<Detail>
component exported with withRouter
– Gabriele Petrioli
Nov 19 '18 at 14:11
@GabrielePetrioli I do not know it. Can you explain me?
– Hai Tien
Nov 19 '18 at 14:11
@GabrielePetrioli I do not know it. Can you explain me?
– Hai Tien
Nov 19 '18 at 14:11
Please show the code with your
Detail
component.– Gabriele Petrioli
Nov 19 '18 at 14:17
Please show the code with your
Detail
component.– Gabriele Petrioli
Nov 19 '18 at 14:17
@GabrielePetrioli Thank you so much. I updated detail component
– Hai Tien
Nov 19 '18 at 14:18
@GabrielePetrioli Thank you so much. I updated detail component
– Hai Tien
Nov 19 '18 at 14:18
Added answer with a solution.
– Gabriele Petrioli
Nov 19 '18 at 14:23
Added answer with a solution.
– Gabriele Petrioli
Nov 19 '18 at 14:23
|
show 6 more comments
1 Answer
1
active
oldest
votes
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 '18 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 '18 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 '18 at 15:28
1
@HaiTien updated answer
– Gabriele Petrioli
Nov 19 '18 at 16:11
1
@Icepickle fair point. Added it to updated answer
– Gabriele Petrioli
Nov 19 '18 at 16:14
|
show 7 more comments
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',
autoActivateHeartbeat: false,
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
});
}
});
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
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
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 '18 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 '18 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 '18 at 15:28
1
@HaiTien updated answer
– Gabriele Petrioli
Nov 19 '18 at 16:11
1
@Icepickle fair point. Added it to updated answer
– Gabriele Petrioli
Nov 19 '18 at 16:14
|
show 7 more comments
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 '18 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 '18 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 '18 at 15:28
1
@HaiTien updated answer
– Gabriele Petrioli
Nov 19 '18 at 16:11
1
@Icepickle fair point. Added it to updated answer
– Gabriele Petrioli
Nov 19 '18 at 16:14
|
show 7 more comments
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 '18 at 17:35
answered Nov 19 '18 at 14:23
Gabriele PetrioliGabriele Petrioli
149k23197253
149k23197253
Thank you so much but it seems that it does not work. Do you know reason why?
– Hai Tien
Nov 19 '18 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 '18 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 '18 at 15:28
1
@HaiTien updated answer
– Gabriele Petrioli
Nov 19 '18 at 16:11
1
@Icepickle fair point. Added it to updated answer
– Gabriele Petrioli
Nov 19 '18 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 '18 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 '18 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 '18 at 15:28
1
@HaiTien updated answer
– Gabriele Petrioli
Nov 19 '18 at 16:11
1
@Icepickle fair point. Added it to updated answer
– Gabriele Petrioli
Nov 19 '18 at 16:14
Thank you so much but it seems that it does not work. Do you know reason why?
– Hai Tien
Nov 19 '18 at 14:32
Thank you so much but it seems that it does not work. Do you know reason why?
– Hai Tien
Nov 19 '18 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 '18 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 '18 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 '18 at 15:28
@GabrielePetrioli Wouldn't that be info that should be part of the answer instead of as a comment? :)
– Icepickle
Nov 19 '18 at 15:28
1
1
@HaiTien updated answer
– Gabriele Petrioli
Nov 19 '18 at 16:11
@HaiTien updated answer
– Gabriele Petrioli
Nov 19 '18 at 16:11
1
1
@Icepickle fair point. Added it to updated answer
– Gabriele Petrioli
Nov 19 '18 at 16:14
@Icepickle fair point. Added it to updated answer
– Gabriele Petrioli
Nov 19 '18 at 16:14
|
show 7 more comments
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
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 '18 at 14:11
@GabrielePetrioli I do not know it. Can you explain me?
– Hai Tien
Nov 19 '18 at 14:11
Please show the code with your
Detail
component.– Gabriele Petrioli
Nov 19 '18 at 14:17
@GabrielePetrioli Thank you so much. I updated detail component
– Hai Tien
Nov 19 '18 at 14:18
Added answer with a solution.
– Gabriele Petrioli
Nov 19 '18 at 14:23