最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - reactjs setState before render on update - Stack Overflow

programmeradmin2浏览0评论

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
Add a ment  | 

1 Answer 1

Reset to default 8

The 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) {
    ...
}
发布评论

评论列表(0)

  1. 暂无评论