Whinegum
Whinegum

Reputation: 13

ReactJS: Problem with rendering component state

I'm new to React and trying to set up a form which upon hitting submit, should set the component state equal to the user entry so that I can store it and reference it elsewhere. This works as the console logs the correct string after submitting. However I run into trouble when trying to display this state on screen.

I've tried passing the state as a prop to a child component and have it rendered there, but I run into the same error.

import React from 'react';
var hasSetMainGoal = false;

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

        this.state = {
                maingoal: ''
        };

        this.handleInput = this.handleInput.bind(this);
        this.updateMainGoal = this.updateMainGoal.bind(this);
    }

    handleInput(e) {
        this.setState({ maingoal: e.target.value });
    }

    updateMainGoal = ({ target }) => {
        this.setState({ maingoal: target});
        console.log('My main goal is ' + this.state.maingoal);
        hasSetMainGoal = true;

    }

    render() {

        if (!hasSetMainGoal) {
        return (
            <div>
                <div className='setGoals'>
                    <div className='formField'>
                        <label className='formFieldLabel'>What is your main learning goal?</label>

                        <input type='text' id='mainGoal' className='formFieldInput' 
                        placeholder='' name='maingoal' value={this.state.value} onChange={this.handleInput} />
                    </div>

                    <div>
                        <button onClick={this.updateMainGoal}>Submit</button>
                    </div>
                </div>


            </div>
        );
        }
        else if (hasSetMainGoal) {

            return (
                <div>
                    <h1>My main goal is {this.state.maingoal}</h1>
                </div>
            );
        }
    }
}

export default LearningGoals;

I would want to have {this.state.maingoal} displayed on screen, but instead I get the following error:

react-dom.development.js:57 Uncaught Invariant Violation: Objects are not valid as a React child (found: [object HTMLButtonElement]). If you meant to render a collection of children, use an array instead. in h1 (at SetGoals.js:55) in div (at SetGoals.js:54)

Upvotes: 1

Views: 76

Answers (2)

Jay85
Jay85

Reputation: 136

Rather than setting hasSetMainGoal as variable, set it in state as false.

So rather than:

var hasSetMainGoal = false;

Do:

this.state = {
                maingoal: '',
                hasSetMainGoal: false
        };

and then set accordingly on button click, and check as:

if (!this.state.hasSetMainGoal) {
}
else if (this.state.hasSetMainGoal) {

       //your code
    );
 }

Upvotes: 0

Vencovsky
Vencovsky

Reputation: 31693

Why you are getting this error

Your problem is in here, where you set the state to target but target is an object.

updateMainGoal = ({ target }) => {
    //                        target is an object
    this.setState({ maingoal: target});
    console.log('My main goal is ' + this.state.maingoal);
    hasSetMainGoal = true;
}

And when you try to render it, it fails because you can't render objects.

else if (hasSetMainGoal) {

    return (
        <div>
            <h1>My main goal is {this.state.maingoal}</h1>
        </div>
    );
}

And if you look at the error

Objects are not valid as a React child (found: [object HTMLButtonElement])

[object HTMLButtonElement] is the target of this.setState({ maingoal: target})

How to solve it

You shouldn't be doing this.setState({ maingoal: target}); in updateMainGoal. Your state is already up to date when the user types in the input and handleInput sets the state for you.

What you should do is keep hasSetMainGoal in the state and set that when you click the button.

Here is the full component code

import React from 'react';

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

        this.state = {
                maingoal: '',
                hasSetMainGoal: false
        };

        this.handleInput = this.handleInput.bind(this);
        this.updateMainGoal = this.updateMainGoal.bind(this);
    }

    handleInput(e) {
        this.setState({ maingoal: e.target.value });
    }

    updateMainGoal = () => {
        this.setState({ hasSetMainGoal : true});
        console.log('My main goal is ' + this.state.maingoal);
    }

    render() {

        if (!this.state.hasSetMainGoal) {
        return (
            <div>
                <div className='setGoals'>
                    <div className='formField'>
                        <label className='formFieldLabel'>What is your main learning goal?</label>

                        <input type='text' id='mainGoal' className='formFieldInput' 
                        placeholder='' name='maingoal' value={this.state.value} onChange={this.handleInput} />
                    </div>

                    <div>
                        <button onClick={this.updateMainGoal}>Submit</button>
                    </div>
                </div>


            </div>
        );
        }
        else {

            return (
                <div>
                    <h1>My main goal is {this.state.maingoal}</h1>
                </div>
            );
        }
    }
}

export default LearningGoals;

Upvotes: 1

Related Questions