0

I'm trying to set a class dynamically depending on the pros i send to the component. Somehow i get the error " Cannot read property 'state' of undefined". I guess that this doesn't exist when i try to set the class of the state as a class? Do i have to rebind it before i use it in the render of the component?

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

class Button extends React.Component {
    constructor(props) {
        super(props);
        console.log("BUTTON")
        console.log(props);

        this.state = {
            class: "small-button"
        };

        props.options.map(function (option) {
            if (option.Description > 10) {
                this.setState({
                    class: "big-button"
                });
            }
        });
        console.log("STATE: " + this.state.class);
    }

    render() {
        if (this.props.options) {
            return (<div> {
                this.props.options.map(function (option) {
                    return <div className={ this.state.class === 'big-button' ? 'option-button big-button' : 'option-button small-button'} key={option.Id}> {option.Description}</div>
                })
            }
            </div>
            )
        } else {
            return <div>No options defined</div>
        }
    }
}

module.exports = Button;
Jankapunkt
  • 8,128
  • 4
  • 30
  • 59
Daniel Gustafsson
  • 1,725
  • 7
  • 37
  • 78
  • its' a binding issue, use `arrow function`: `this.props.options.map( (option) => { .....` **one suggestion:** don't put logic inside `constructor` and don't do `setState` also, use lifecycle method for that. Put that logic inside `componentDidMount` method or `componentWillMount` method :) – Mayank Shukla May 05 '17 at 12:07
  • Thanks but i'm super new to react, could you provide me with a bigger code example what you mean by arrow function? – Daniel Gustafsson May 05 '17 at 12:11

1 Answers1

1

It's a binding issue, you need to bind the function to use this keyword (correct context) inside that.

Use this:

render() {
        if (this.props.options) {
            return (<div> {
                this.props.options.map((option) => {
                    return <div className={ this.state.class === 'big-button' ? 'option-button big-button' : 'option-button small-button'} key={option.Id}> {option.Description}</div>
                })
            }
            </div> )
        } else {
            return <div>No options defined</div>
        }
    }

Check this answer for more detail on arrow function and this keyword

One Suggestion: Don't put logic inside constructor and don't do setState also, use lifecycle method for that. Put that logic inside componentDidMount method or componentWillMount method.

Like this:

class Button extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            class: "small-button"
        };
    }

    componentDidMount(){
        this.props.options.forEach((option) => {
            if (option.Description > 10) {
                this.setState({
                    class: "big-button"
                });
            }
        });
    }

    render() {
        if (this.props.options) {
            return (
                <div> 
                {
                    this.props.options.map((option) => {
                        return <div className={ this.state.class === 'big-button' ? 'option-button big-button' : 'option-button small-button'} key={option.Id}> {option.Description}</div>
                    })
                }
                </div>
            )
        }else{
            return <div>No options defined</div>
        }
    }
}
Community
  • 1
  • 1
Mayank Shukla
  • 100,735
  • 18
  • 158
  • 142
  • so this.props.options.map((option) => { instead of this.props.options.map(function(option){ makes is bind the new state? – Daniel Gustafsson May 05 '17 at 12:18
  • @DanielGustafsson it will not `bind` the `state`, it will `bind` the `context` means if you don't bind, `this` keyword will not refer to `react class component` and `this.state` will be undefined, you code will also work if you just remove the `this` keyword inside map body, simply return a span it will not throw error. – Mayank Shukla May 05 '17 at 12:22
  • @DanielGustafsson check the updated answer, attached a very useful link, it will help you to understand the role of this keyword. – Mayank Shukla May 05 '17 at 12:28