setState is receiving invalid React child

Tell us what’s happening:
setDisplay() method should take a click event and set state accordingly.

I am receiving following error message:
" Objects are not valid as a React child (found: object with keys {count, tempcount}).
If you meant to render a collection of children, use an array instead."

It appears that merhod is taking component state as parameter, instead of the value that is taken from the click event.

This does not make much sence to me and I do not have debugging skills to investigate further.

May I kindly ask someone for help.

Many thanks in advance.

P.S.
I should add that I am trying my best in solving problems, but. more often than not apparently, I am puzzled with what to do.
I do hope my asking for help will decrease as I get more experienced.

Your code so far

const digits = [
  ["zero", 0],
  ["one", 1],
  ["two", 2],
  ["three", 3],
  ["four", 4],
  ["five", 5],
  ["six", 6],
  ["seven", 7],
  ["eight", 8],
  ["nine", 9]
];
const operators = [
  ["add", "+"],
  ["subtract", "-"],
  ["multiply", "*"],
  ["divide", "/"],
  ["decimal", "."],
  ["equals", "="],
  ["clear", "AC"]
];



class Calculator extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0,
      tempcount: 0
    };

    this.setDisplay = this.setDisplay.bind(this);
  }

  

  // take value from the event listener and set state.tempcount to this value.
  //tempcount should then be rendered to the screen within div with id='display'
  
  setDisplay() {
        this.setState(e=>({
      tempcount:e
    }));
  } 
  
    render() {

   // console.log(this.state.tempcount)
    //render numbers to the screen
    const padDigits = digits.map((arr, num, dig) => {
    //console.log(arr[1]);
      return (
        <button id={arr[0]} className="buttons" onClick={this.setDisplay} value={arr[1]}>
          {num}
        </button>
      );
    });

    //render operators to the screen
    const padOperators = operators.map((arr, oper, arrArr) => {
      return (
        <button id={arr[0]} className="buttons">
          {arr[1]}
        </button>
      );
    });
    return (
      <div id="container">
        <div id="display">{this.state.tempcount}</div>
        <div id="digits">{padDigits}</div>
        <div id="operators">{padOperators}</div>
      </div>
    );
  }
}

ReactDOM.render(<Calculator />, document.getElementById("App"));

Your browser information:

User Agent is: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36

Challenge: Build a JavaScript Calculator

Link to the challenge:

1 Like

That error means that you are trying to send an object to the screen. React doesn’t like this. That is happening here:

<div id="display">{this.state.tempcount}</div>

It is happening because of this:

setDisplay() {
  this.setState(e=>({ tempcount: e }));
} 

What is e in that? setState is passing in the previous state as the first parameter. You are then taking that entire state (an object) and saving it onto the state.tempcount. If you want the click event, you need to accept it into the setDisplay method and parse it to get the value that you want and then save that value onto that property.

Does that make sense?

A quick diagnostic tool to try to see what is happening would be to put:

console.log(this.state.tempcount);

into your render method and see how that transmogrifies.

Hi Kevin,
It as always great talking to you.

The itention of the e is to take value from click event

<button id={arr[0]} className="buttons" onClick={this.setDisplay} value={arr[1]}>

I am trying to pass value={arr[1] to setDisplay.

Value should be taken from:

const padDigits = digits.map((arr, num, dig) => {
    //console.log(arr[1]);
      return (
        <button id={arr[0]} className="buttons" onClick={this.setDisplay} value={arr[1]}>
          {num}
        </button>
      );
    });

As I do the click on the calculator, number 1,2,3,etc. should be set as tempcount value within the state .
That is what e should do.
Instead, it is taking the current state and trying to set as a value of tempcount.
Don’t know why.

P.S. Thanks a bunch for responding.

Finally. I deleted comments as they went a bit astray to my personal view of my programming success…which is a bit rude.

Right, I get that. This is a pretty standard thing. The issue is - How is that click going to get into your handler method?

You are passing it the reference to the method like this:

onClick={this.setDisplay}

That means that the onClick event is just going to pass whatever parameters it has into the method. This is your method:

setDisplay() {
  this.setState(e=>({ tempcount: e }));
} 

Where are you accepting that parameter. You’ve named the parameter in your callback to setState as “e”, but that doesn’t make it the event. That is just a label. You could call it “peanutButterElephant” but it would still be the previous state because that is what setState passes in to the call back - setState doesn’t know or care what you’re going to call it.

You are not doing anything with the click event. At this point, I would recommend doing what professional developers do, with our super secret trick. DO NOT tell anyone this super secret unless they know the secret handshake: we good google it. Seriously. Google “react onclick event”. Read through some of those and see if you can get a better understanding.

1 Like

Hi @Deyan11 .
Kevin trying to explain it and ill try to put it too.
The event handler in your case is setDisplay. The event handler is the one which, by default, gets the event object passed to it. Unfortunately, you dont make your event handler aware of that object. Look here:

setDisplay(/*this is empty*/) {
        this.setState(e=>({tempcount:e}))
  }

Your event handler has no parameters. Its not aware of no event object passed to it. You dont have access to the event object in its body. However, you have the e argument in your setState method. What is e in the current context? Its the current state. You take the current state and convert it to new value: {tempcount: currentState}. Initially, your current state would be { count: 0, tempcount: 0}. So when you call the setState the way you do, the state will become {tempcount: {count: 0, tempcount: 0}}. Then, this same object is passed in your html:

<div id="display">{this.state.tempcount}</div>

Obviously, the compiled is not very happy about it, as you are trying to render javascript object on the DOM, when it expects some text value, or another element, a valid React component, which ultimately represents a html element. It would even be happy if you were to pass a JS array actually, which the compiled can decypher as list of html elements(as long as the elemnts in the array are valid elements html can work with, from the ones i just listed).

I hope this explanation will help you udnerstand where your code logic fails and how to implement what you actually want. Dont forget to place here and there console logs, to see where you expect some value to be available and with certain shape, but its not. You can log what this.state.tempcount represents in the render method and see its a value html cant work with. You can console log the e value in your setState method and see its not the event object you are expecting and maybe you will recall its your old state. You might even decide to log something in the setDisplay method and realize there is nothing to log and it gets no event data ^^.

2 Likes

If all you need is the number you don’t need the event. You can just pass num to the handler function (and make sure it accepts the argument, i.e it has to have a parameter).

setDisplay(number) {
  this.setState({ tempcount: number});
}


onClick={() => this.setDisplay(num)}
2 Likes

Hi Sylvant,

I changedI changed handling method according to this:

setDisplay(e) {
        this.setState({
      tempcount:e
    });
  } 

I checked with console.log(this.state.tempcount) and it gave me a bunch of nulls.

I then thoutght that setDiplay (e ) is not receiving properly from

<button id={arr[0]} className="buttons" onClick={this.setDisplay} value={arr[1]}>

I then deleted the onClick from the button element and added an event listener in following way:

 compomemtDidMoint(){
    document.addEventListener('keydown',this.setDisplay)
  }
  
  componentWillUnmount(){
    documetn.addEventListener('keydown',this.setDisplay)
  }

This worked well in my previous project.

Now, when I press the button on the calculator, it is not triggering any event.
I Googled it, but couldn`t find a case specific similar to this.

May I ask for more help.

Perhaps I should mention that my purpose is to get certificated for the Front End, to complete the project.
Don’t know if I will get fully comfortable with what I have learned, or do better with other programming languages (SQL, Python, etc.).

Look,

This is the standard way to get a click event:

class App extends React.Component {
  state = { count: 0 }
 
  handleClicks = e =>
    this.setState(ps => ({ count: ps.count + +e.target.value }))
  
  render() {
    return (
      <div> 
        <button value="1" onClick={ this.handleClicks }>inc</button>
        <button value="-1" onClick={ this.handleClicks }>dec</button>
        <p>The count: { this.state.count }</p>
      </div>
    )
  }
}

There is a working pen here.

As lasjorg points out, you can also pass in data to your handler function. In some cases you may want to do both.

2 Likes

Try this test suite to check what the event object represents:

<button onClick{this.handleClick} >test</button>
handleClick=e=>console.log(e)

On your console, you should see the event object, is indeed object, with a lot of properties and data attached. You need to know what you look for. For example e.target would retrieve the DOM element, which triggered the event(the button). You cant just pass the whole event object as a property in the state and then put it in the JSX as an element, or some data, because its not valid data the html can work with. You need to determine what data you need to use from the event object

1 Like

Thank you all very much. I appreciate it.

Hi Kevin,
Sorry to bother you again. I was wondering if I could get more help from you.

I tried implemented the method in a correct way. It can not read value from the buttton. Can’t find why. It could be I Googled the wrong posts, but none gave me a clue where to look.

I’ve been involved with important and pressing concerns in the past period, and not really able to see this project through. I should be able to catch up though.

I actually do hope to make a living out of this…some day…so it is all the more imoprtant to get this right.

In case this is too much to ask, no issues. I’ll just stop asking.

Bellow is my code. Thanks in advance.

class Calculator extends React.Component {
  state = {
    count: '0',
    tempcount: '0'
  };

  handleClick = e =>
    this.setState(tc => ({tempcount: e.target.value}))
  
  
  
  render() {
    
   console.log(this.state.tempcount)
    return (
      <div id="container">
        <div id='display'>
          {this.state.tempcount}
          
        </div>
        <div className="buttons">
          <div id="digits">
            <button id="zero" value='0' onClick={this.handleClick}>
              0
            </button>
            <button id="one" value='1' onClick={this.handleClick}>
              1
            </button>
            <button id="two" value='2' onClick={this.handleClick}>
              2
            </button>
            <button id="three" value='3' onClick={this.handleClick}>
              3
            </button>
            <button id="four" value='4' onClick={this.handleClick}>
              4
            </button>
            <button id="five" value='5' onClick={this.handleClick}>
              5
            </button>
            <button id="six" value='6' onClick={this.handleClick}>
              6
            </button>
            <button id="seven" value='7' onClick={this.handleClick}>
              7
            </button>
            <button id="eight" value='8' onClick={this.handleClick}>
              8
            </button>
            <button id="nine" value='9' onClick={this.handleClick}>
              9
            </button>
          </div>
<div id='operators'>
          <button id="add" onClick={this.handleClick}>
            +
          </button>
          <button id="subtract" onClick={this.handleClick}>
            -
          </button>
          <button id="multiply" onClick={this.handleClick}>
            *
          </button>
          <button id="divide" onClick={this.handleClick}>
            /
          </button>
  <button onClick={this.handleClick}>
            =
          </button>
  <button onClick={this.handleClick}>
            .
          </button>
  
  
        </div>
        
        </div>
      </div>
    );
  }
}

ReactDOM.render(<Calculator />, document.getElementById("App"));

What version of React are you using?

It should work just fine with React 17. But your setState won’t work in React 16 because of the setState updater function you are using. If so, use event.persist() at the top of the handler function. Or if you do not plan on using the current state don’t use an update function.

handleClick = (e) => {
  e.persist()
  this.setState((tc) => ({ tempcount: e.target.value }));
};

Otherwise, your code works for me so you will have to explain exactly what it is that isn’t working for you?


2 Likes

Also, you really do not need the event here. Hardcoding an attribute value is no different from hardcoding an argument to the handler function. Just pass the handler the number.

1 Like