0

I'm changing the class attribute of my props and then i want the component to rerender with the new classes but that doesn't work. I've read about the shouldComponentUpdate method but that method never gets called.

  var ReactDOM = require('react-dom');
  var React = require('react');

   class Button extends React.Component {
constructor(props) {
    super(props);
    console.log("BUTTON")
    console.log(props);
    var options = props.options;
}
componentWillMount () {
    var defaultFeatureOptionId = this.props.feature.DefaultFeatureOptionId;
    this.props.options.forEach((option) => {
        var classes = "";
        if (option.Description.length > 10) {
            classes = "option-button big-button hidden";
        } else {
            classes = "option-button small-button hidden";
        }
        if (option.Id === defaultFeatureOptionId) {
            classes = classes.replace("hidden", " selected");
            option.selected = true;
        }
        option.class = classes;
    });
}
shouldComponentUpdate(props) {
    console.log("UPDATE");
}
toggleDropdown(option, options) {
    console.log(option);
    console.log(options)

    option.selected = !option.selected;
    options.forEach((opt) => {
        if (option.Id !== opt.Id) {
            opt.class = opt.class.replace("hidden", "");
        }
        else if(option.Id === opt.Id && option.selected) {
            opt.class = opt.class.replace("", "selected");
        } 
    });        
}
render() {
    if (this.props.options) {
        return (<div> {
            this.props.options.map((option) => {
                return <div className={ option.class } key={option.Id}>
                    <div> {option.Description}</div>
                    <img className="option-image" src={option.ImageUrl}></img>
                    <i className="fa fa-chevron-down" aria-hidden="true" onClick={() => this.toggleDropdown(option, this.props.options) }></i>
                    </div>
            })
        }

        </div>
        )
    }     
    else {
        return <div>No options defined</div>
    }
}
 }

 module.exports = Button;

I have read a lot of different thing about shouldComponentUpdate and componentWillReceiveProps but there seems to be something else i'm missing.

Daniel Gustafsson
  • 1,725
  • 7
  • 37
  • 78
  • according to a blog i read "A re-render can only be triggered if a component’s state has changed. The state can change from a props change, or from a direct setState change. The component gets the updated state and React decides if it should re-render the component. " both the props and state will trigger state change – Daniel Gustafsson May 09 '17 at 06:45

1 Answers1

1

You cannot change the props directly, either you call a parent function to change the props that are passed to your component or in your local copy that you createm you can change them. shouldComponentUpdate is only called when a state has changed either directly or from the props, you are not doing any of that, only modifying the local copy and hence no change is triggered

Do something like

var ReactDOM = require('react-dom');
var React = require('react');

   class Button extends React.Component {
constructor(props) {
    super(props);
    console.log(props);
    this.state = {options = props.options};
}
componentWillRecieveProps(nextProps) {
  if(nextProps.options !== this.props.options) {
    this.setState({options: nextProps.options})
  }
}
componentWillMount () {
    var defaultFeatureOptionId = this.props.feature.DefaultFeatureOptionId;
    var options = [...this.state.options]
    options.forEach((option) => {
        var classes = "";
        if (option.Description.length > 10) {
            classes = "option-button big-button hidden";
        } else {
            classes = "option-button small-button hidden";
        }
        if (option.Id === defaultFeatureOptionId) {
            classes = classes.replace("hidden", " selected");
            option.selected = true;
        }
        option.class = classes;
    });
    this.setState({options})
}
shouldComponentUpdate(props) {
    console.log("UPDATE");
}
toggleDropdown(index) {

    var options = [...this.state.options];
    var options = options[index];
    option.selected = !option.selected;
    options.forEach((opt) => {
        if (option.Id !== opt.Id) {
            opt.class = opt.class.replace("hidden", "");
        }
        else if(option.Id === opt.Id && option.selected) {
            opt.class = opt.class.replace("", "selected");
        } 
    });   
    this.setState({options})
}
render() {
    if (this.state.options) {
        return (<div> {
            this.state.options.map((option, index) => {
                return <div className={ option.class } key={option.Id}>
                    <div> {option.Description}</div>
                    <img className="option-image" src={option.ImageUrl}></img>
                    <i className="fa fa-chevron-down" aria-hidden="true" onClick={() => this.toggleDropdown(index) }></i>
                    </div>
            })
        }

        </div>
        )
    }     
    else {
        return <div>No options defined</div>
    }
}
 }

 module.exports = Button;
Shubham Khatri
  • 270,417
  • 55
  • 406
  • 400
  • What do you mean when you write this: [...this.state.options] ? – Daniel Gustafsson May 09 '17 at 07:05
  • if i use this.state.options then state will be null. I can use this.setState.options but that is wrong i assume since that is the method used to acctually set the state? – Daniel Gustafsson May 09 '17 at 07:11
  • See this answer http://stackoverflow.com/questions/42811882/what-is-the-meaning-of-this-syntax-x-in-reactjs/42811937#42811937 to understand what `[...this.state.options]` mean, it creates a duplicate object and wraps within a array in short and is known as spread operator syntax – Shubham Khatri May 09 '17 at 07:14
  • even if the constructor gets called first and sets the state. the var options = [...this.state.options]; in componentWillMount then state will still be null. However this.setState is not. Why is not the state set properly in the constructor? – Daniel Gustafsson May 09 '17 at 07:21
  • never mind. I typed this.setState instead of this.state in the constructor. – Daniel Gustafsson May 09 '17 at 07:34
  • No you should be setting the state in constructor like this.state= {} and not this.setState, it may have happened because initially the props are not avaiable from your parent. – Shubham Khatri May 09 '17 at 08:26