I have a react ponent and the requirement is to setState before render on update (url hash change). Below is code snippet:
ponentConfig: function() {
.....
this.setState({rows: rows});
this.setState({loadMoreBtn: loadMoreIsVisible})
},
I was it working before, I was calling this method from getInitialState
and it was working fine. getInitialState
fires only once so I was not able to update it on url change. I tried various other inbuilt update methods such as ponentWillReceiveProps
but they are one step behind. Seems like render happens before this method gets called. I also tried to call it from render
but obviously states get confused and it breaks.
As this image demonstrates, ponentRillReceiveProps
always behind render. I need something that fires before render each time on url update. Hope it makes sense.
or in other words, I would like to fire getInitialState
on hash change.
var React = require('react'),
projectsData = require('./../projects'),
ProjectsRow = require('./projects_row'),
itemsInRow = 3,
noOfDefaultRows = 2,
projects = [],
currentProjects = [],
currentPageRows,
currentParamKey;
var Projects = React.createClass({
ponentWillMount: function() {
thisponentConfig(this.props);
},
ponentWillReceiveProps: function(nextProps){
thisponentConfig(nextProps);
},
ponentConfig: function(props) {
var rows = [],
currentParamKey = 'projects',
loadMoreIsVisible = true,
i;
if(props.params.key) {
currentParamKey = props.params.key;
}
projects = projectsData.getByKey(currentParamKey);
projectsData.currentState[currentParamKey] = noOfDefaultRows;
currentProjects = projects.slice(); //Create a copy or array
noOfDefaultRows = projectsData.currentState[currentParamKey] || noOfDefaultRows;
for (i = 0; i < noOfDefaultRows; i++) {
if(currentProjects.length) {
rows.push(currentProjects.splice(0, itemsInRow));
}
}
currentProjects.length ? loadMoreIsVisible = true : loadMoreIsVisible = false;
this.setState({rows: rows});
this.setState({loadMoreBtn: loadMoreIsVisible})
console.log('Finished executing ponentConfig and currentParamKey = ' ,currentParamKey);
},
loadMoreProjects: function(e) {
e.preventDefault();
var addRow = this.state.rows;
if(currentProjects.length) {
currentPageRows++;
addRow.push(currentProjects.splice(0, itemsInRow));
this.setState({rows: addRow});
}
if(!currentProjects.length) {
this.setState({loadMoreBtn: false})
}
},
render: function() {
console.log('Now in render and currentParamKey = ' ,currentParamKey);
var projectUrl;
//currentParamKey = this.props.params.key;
if(currentParamKey === 'projects') {
projectUrl = '#/project';
} else {
projectUrl = '#/project/' + currentParamKey
}
return (
< div className="projects">
< div className = "jumbotron" >
< div className = "container" >
< h1 > Projects < /h1>
< /div>
< /div>
< div className = "container" >
{this.state.rows.map(function(row, i) {
return <ProjectsRow url={projectUrl} row={row} key={i} />
}.bind(this))}
< /div>
< div className = "container text-center" >
<a id="loadMore" className= {this.state.loadMoreBtn ? 'linkStyle1' : 'hide'}
onClick = {this.loadMoreProjects}
role="button" > <i className="fa fa-angle-down"></i><span>Load More Projects</span>
</a>
<br />
<br />
<div className="contact-me-link">
<a className="linkStyle1" href="#/contact">
<i className="fa fa-angle-right"></i><span>Contact</span>
</a>
</div>
</div>
< /div>
);
}
});
module.exports = Projects;
I have a react ponent and the requirement is to setState before render on update (url hash change). Below is code snippet:
ponentConfig: function() {
.....
this.setState({rows: rows});
this.setState({loadMoreBtn: loadMoreIsVisible})
},
I was it working before, I was calling this method from getInitialState
and it was working fine. getInitialState
fires only once so I was not able to update it on url change. I tried various other inbuilt update methods such as ponentWillReceiveProps
but they are one step behind. Seems like render happens before this method gets called. I also tried to call it from render
but obviously states get confused and it breaks.
As this image demonstrates, ponentRillReceiveProps
always behind render. I need something that fires before render each time on url update. Hope it makes sense.
or in other words, I would like to fire getInitialState
on hash change.
var React = require('react'),
projectsData = require('./../projects'),
ProjectsRow = require('./projects_row'),
itemsInRow = 3,
noOfDefaultRows = 2,
projects = [],
currentProjects = [],
currentPageRows,
currentParamKey;
var Projects = React.createClass({
ponentWillMount: function() {
this.ponentConfig(this.props);
},
ponentWillReceiveProps: function(nextProps){
this.ponentConfig(nextProps);
},
ponentConfig: function(props) {
var rows = [],
currentParamKey = 'projects',
loadMoreIsVisible = true,
i;
if(props.params.key) {
currentParamKey = props.params.key;
}
projects = projectsData.getByKey(currentParamKey);
projectsData.currentState[currentParamKey] = noOfDefaultRows;
currentProjects = projects.slice(); //Create a copy or array
noOfDefaultRows = projectsData.currentState[currentParamKey] || noOfDefaultRows;
for (i = 0; i < noOfDefaultRows; i++) {
if(currentProjects.length) {
rows.push(currentProjects.splice(0, itemsInRow));
}
}
currentProjects.length ? loadMoreIsVisible = true : loadMoreIsVisible = false;
this.setState({rows: rows});
this.setState({loadMoreBtn: loadMoreIsVisible})
console.log('Finished executing ponentConfig and currentParamKey = ' ,currentParamKey);
},
loadMoreProjects: function(e) {
e.preventDefault();
var addRow = this.state.rows;
if(currentProjects.length) {
currentPageRows++;
addRow.push(currentProjects.splice(0, itemsInRow));
this.setState({rows: addRow});
}
if(!currentProjects.length) {
this.setState({loadMoreBtn: false})
}
},
render: function() {
console.log('Now in render and currentParamKey = ' ,currentParamKey);
var projectUrl;
//currentParamKey = this.props.params.key;
if(currentParamKey === 'projects') {
projectUrl = '#/project';
} else {
projectUrl = '#/project/' + currentParamKey
}
return (
< div className="projects">
< div className = "jumbotron" >
< div className = "container" >
< h1 > Projects < /h1>
< /div>
< /div>
< div className = "container" >
{this.state.rows.map(function(row, i) {
return <ProjectsRow url={projectUrl} row={row} key={i} />
}.bind(this))}
< /div>
< div className = "container text-center" >
<a id="loadMore" className= {this.state.loadMoreBtn ? 'linkStyle1' : 'hide'}
onClick = {this.loadMoreProjects}
role="button" > <i className="fa fa-angle-down"></i><span>Load More Projects</span>
</a>
<br />
<br />
<div className="contact-me-link">
<a className="linkStyle1" href="#/contact">
<i className="fa fa-angle-right"></i><span>Contact</span>
</a>
</div>
</div>
< /div>
);
}
});
module.exports = Projects;
Share
Improve this question
edited Jul 29, 2015 at 17:07
JS-JMS-WEB
asked Jul 29, 2015 at 13:11
JS-JMS-WEBJS-JMS-WEB
2,6253 gold badges18 silver badges26 bronze badges
3
- ponentWillReceiveProps should run before the next render cycle. Could you post a bit more code to give us a better idea of what you are doing? – noveyak Commented Jul 29, 2015 at 13:16
- Did you notice that ponentWillReceiveProps will give the new state as an argument, so it's only this.state that is one step behind? – Seppo420 Commented Jul 29, 2015 at 13:17
- @Seppo420, it takes an array of projects depending on url. So if I go to /xml and then /html. /html will contain /xml projects. – JS-JMS-WEB Commented Jul 29, 2015 at 13:21
1 Answer
Reset to default 8The ponentWillReceiveProps get new props as a parameter. The old props remain unchanged on this method execution, so you need to initialize your state based on this parameter. Try passing the props as a parameter to your ponentConfig method:
ponentWillMount: function() {
this.ponentConfig(this.props);
},
ponentWillReceiveProps: function(nextProps){
this.ponentConfig(nextProps);
},
ponentConfig: function(data) {
...
}