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;
2
  • 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 :) Commented May 5, 2017 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? Commented May 5, 2017 at 12:11

1 Answer 1

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>
        }
    }
}
Sign up to request clarification or add additional context in comments.

3 Comments

so this.props.options.map((option) => { instead of this.props.options.map(function(option){ makes is bind the new state?
@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.
@DanielGustafsson check the updated answer, attached a very useful link, it will help you to understand the role of this keyword.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.