Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

reactjs setState before render on update

I have a react component and the requirement is to setState before render on update (url hash change). Below is code snippet:

componentConfig: 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 componentWillReceiveProps 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.

enter image description here

As this image demonstrates, componentRillReceiveProps 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({

    componentWillMount: function() {
        this.componentConfig(this.props);
    }, 

    componentWillReceiveProps: function(nextProps){
        this.componentConfig(nextProps);
    },

    componentConfig: 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 componentConfig 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;
like image 1000
JS-JMS-WEB Avatar asked Jul 29 '15 13:07

JS-JMS-WEB


People also ask

How do you setState before render in React?

To answer your question, yes there is a way to setState before the initial render and that is with componentWillMount . It is the first lifecycle method to be called in React. The lifecycle method componentDidMount is called after the initial render.

Is setState called before render?

Yes. It calls the render() method every time we call setState only except when shouldComponentUpdate returns false .

Can we setState in render method React?

render() Calling setState() here makes it possible for a component to produce infinite loops. The render() function should be pure, meaning that it does not modify a component's state. It returns the same result each time it's invoked, and it does not directly interact with the browser.

Can we use setState in componentDidMount?

You may call setState() immediately in componentDidMount() . It will trigger an extra rendering, but it will happen before the browser updates the screen. This guarantees that even though the render() will be called twice in this case, the user won't see the intermediate state.


1 Answers

The componentWillReceiveProps 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 componentConfig method:

componentWillMount: function() {
    this.componentConfig(this.props);
}, 
componentWillReceiveProps: function(nextProps){
    this.componentConfig(nextProps);
},
componentConfig: function(data) {
    ...
}
like image 125
const314 Avatar answered Sep 20 '22 21:09

const314