Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reactjs setState arrow function syntax

As per the React Docs we can have two ways for setState one with object syntax and other with function which they have shown as below

this.setState((prevState, props) => ({
  counter: prevState.counter + props.increment
}));

My understanding of arrow function syntax is like () => {} where flower brackets are followed after arrow =>, but as per the sample it is round braces instead of flower brackets

What is the difference between these syntax ()=>{} and ()=>({}).

Sample Code tried as per the docs which is working when this.setStage(prevStage=>({})) syntax is used in handleClick function, and if you change it to this.setState(prevStage=>{}) it wont toggle the button value.

Below is the working code:

class Toggle extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            isToggleOn : true
        }
        this.handleClick = this.handleClick.bind(this);
    }

    handleClick() {
        this.setState(prevState => ({
            isToggleOn: !prevState.isToggleOn
          }));
    }

    render() {
        return (
            <div>
                <button onClick={this.handleClick}>
                    {this.state.isToggleOn ? 'ON' : "OFF"}
                </button>
            </div>
        );
    }
}
like image 498
Chandre Gowda Avatar asked Dec 28 '17 07:12

Chandre Gowda


People also ask

How do I use setState in React JS?

The setState() Method State can be updated in response to event handlers, server responses, or prop changes. This is done using the setState() method. The setState() method enqueues all of the updates made to the component state and instructs React to re-render the component and its children with the updated state.

What does => means in React?

The () => { ... } is the function. It's an ES6-style "arrow" function expression. These are like function expressions ( tick = function() { ... } ) except that the this value within the function is inherited from the context in which it's defined rather than being set when the function is called.

What does the setState () function do?

Note how setState() works. You pass it an object containing part(s) of the state you want to update. In other words, the object you pass would have keys corresponding to the keys in the component state, then setState() updates or sets the state by merging the object to the state. Thus, “set-State”.


2 Answers

There are 2 main issues to consider here:

  1. How arrow functions works?

  2. What setState expects when passing function as a parameter?

Answers:

  1. Arrow functions can return a value implicitly or explicitly.
    When there is no function body (no curly brace {}) then you are returning implicitly:

    const x = () => 'we are returning a string here';  
    

    When we use a function body, we need to use the return key word:

    const x = () => {
      return 'another string returned'
    };
    

    There is another option to return something without the return key word, you can wrap the curly brace with parentheses () and this will signal the engine that the curly brace are not a function body but an object, this is considered as creating an expression:

    const x = () => ({myKey: 'some string'});
    

    This is similar as we usually do with function expressions.
    Especially with IIFE (Immediately Invoked Function Expression) :

    (function() {
        //some logic...
    })();  
    

    If we will not return anything, then the function will just return undefined.

  2. As for setState, when you pass a function as a parameter, it expect that this function will return an object.
    When your function didn't return anything (as stated above) it actually returned undefined.
    JavaScript won't yield an error as this is not an error. its just a function that returns nothing (undefined).

Here is a running example of your code without the wrapping parentheses:

class Toggle extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      isToggleOn: true
    }
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    this.setState(prevState => {
      return { // we must return an object for setState
        isToggleOn: !prevState.isToggleOn
      } 
    });
  }

  render() {
    return (
      <div>
        <button onClick={this.handleClick}>
          {this.state.isToggleOn ? 'ON' : "OFF"}
        </button>
      </div>
    );
  }
}


ReactDOM.render(<Toggle />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>

Edit
As a followup to your comments

I would expect Javascript to throw error when we return just key : value without enclosing parenthesis, i.e., () => {key:value} - which means it is trying to return 'key:value' and not Object, and this should be an JS error, but it did not throw any error. Please correct me if my understanding is wrong

It is not returning a key value, it is a "void" function that returns undefined.
See this running snippet:

const x = () => {myKey: 'myValue'};
const y = x();
console.log(y);

Edit#2
Followup to your other comments (which is basically kind of a whole different question in my opinion).

let y = function() {'abc':1} - syntax error, let y = function(){abc:1} and let y = function(){ return {'abc':1} } - no error, where first one (syntax error) we are trying to assign 1 to string abc, which is same as 3rd sample (no error), and 2nd example assigning 1 to abc - works when there is no quotes. Please explain the difference of these 3 samples and why 1st one fails and not 2nd example

OK, this is getting interesting.

where first one (syntax error) we are trying to assign 1 to string abc...

No we are not.
We are trying to create a label:, but labels can't be strings!
Same as variables can't be strings - var 'x' = 1.

This is a valid syntax in JavaScript:

const y = function(){b:2};

What we are doing here is creating a label: named a and this label has an expression of 1 (we are not doing anything with this label.).

const x = () => {a:1};
const y = function(){a:1};

This syntax is invalid:

const y = function() { 'a': 1 };

This is not valid because labels can't start with a string:

const x = () => { 'a': 1 };
const y = function() { 'a': 1 };

And again, this is not a key:value pair, the curly brace are the function's BODY.

like image 198
Sagiv b.g Avatar answered Sep 28 '22 01:09

Sagiv b.g


Later I referred MDN and found details under Advanced Syntax section, that if you want to return objects implicitly then we need to enclose it within () , that answered my question.

// Parenthesize the body of function to return an object literal expression:

params => ({foo: bar})

like image 40
Chandre Gowda Avatar answered Sep 28 '22 01:09

Chandre Gowda