What determines when a JavaScript ES6 arrow function ends? [duplicate] - javascript

This question already has answers here:
What are the rules for JavaScript's automatic semicolon insertion (ASI)?
(7 answers)
Closed 4 years ago.
I realize that an arrow function body can be contained by brackets, but when it doesn't have brackets, what determines when the function terminates?
I'm not sure if this question is general for ES6 or if it is specific to ReactJS or JSX, but I have the following function in React, and right below it, I have the start of a class declaration, which is not within the scope of the function:
const Search = ({ value, onChange, children }) =>
<form>
{children} <input
type="text"
value={value}
onChange={onChange}
/>
</form>
class Table extends Component {
...
...
...
This appears to be valid. What is it about the function that makes it not include the class declaration? Is it that there is a blank line between them? Is it something specific to JSX? Is it because there is a single container element as the body of the function? Or is it something else?

You can enclose your arrow functions with {}
const doSomething = () => {
// ...
return 'val'; // return statement is optional
}
If your arrow functions have only one line of code, it is implicitly understood that it is a return statement and you don't have to wrap them in {}
For example, both these functions are the same.
// explicit return
const doSomething = () => {
return 'val';
}
// implicit return
const doSomething = () => ('val')
You can write implicit return in a few different ways
// implicit return with ()
const doSomething = () => ('val')
// implicit return without ()
const doSomething = () => 'val'
// implicit return in next line with ()
const doSomething = () =>
('val')
// implicit return in next line without ()
const doSomething = () =>
'val'
This is what React does. Top level <tag> in a React component, when babel transpiled, will return on statement like React.createElement(...)
For example, this
const Search = ({ value, onChange, children }) =>
<form>
{children} <input
type="text"
value={value}
onChange={onChange}
/>
</form>
will be transpiled to
const Search = ({ value, onChange, children }) => React.createElement(...)

You return a single expression in the Search declaration. A compiler reads the declaration ending at the end of that expression (being the closing jsx tag). Personally i prefer to wrap my jsx () => (<div></div>) simply for readability but there's nothing wrong with how your code is.

Related

When to use curly brackets vs curved brackets in React

I'm currently taking an online course to learn React and I'm confused as to when I should be using { vs (.
I have 3 files:
App.js
const App = () => {
card-list.component.jsx
const CardList = ({ monsters }) => (
card.component.jsx
const Card = ({ monster }) => {
This is the code that currently works. Notice that on the second code the last character used is (. I thought of changing it to { to make it consistent with the other files but somehow the card list no longer shows up on the page although I didn't get any compile errors.
Can someone explain this to me and tell me when I should use one over the other?
This essentially is a feature of arrow functions in js.
const myArrowFunc = ({key1}) => ("Hello there! " + key1);
is essentially the same as
const myArrowFunc = ({key1}) => { return "Hello there! " + key1 };
when you leave out the curly brackets, the return is implicit.
When you include the curly brackets, you must explicitly use the return statement.
const someObj = { key1: "value1" };
const someReturn = myArrowFunc(someObj);
console.log(someReturn); // logs "Hello there! value1" to the console
()=>{} is the syntax of arrow function
When an arrow function only contains one line that return a value, e.g.:
() => {
return 1;
}
it can be simplified to
() => 1
Now what if you want to return an object directly? i.e. how to simplify
() => {
return { foo: "bar" }
}
Since an object also use {}, you cannot write {foo: "bar"} directly after the arrow as it will be treated as the function body. Wrapping the object within () solves the problem since a () chunk must be an expression. The above example can be simplified to
() => ( { foo : "bar" } )

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>
);
}
}
There are 2 main issues to consider here:
How arrow functions works?
What setState expects when passing function as a parameter?
Answers:
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.
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.
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})
the simple answer is
()=>({})
also it's equal to
()=> {
return {}
}
return an empty object,here parentheses around {} mean return. also you know we must pass object to setState so we insert any thing we want to state between {}
()=>({any thing you want to set to state})
If you only write () => {} this explicitly means that the function does more than return something.
For example:
const logAndReturn = (val) => {
console.log(val)
return val
}
But let's say you have a function that takes params and returns an object based on those params.
const createUser = (x) => {
prop: x
}
This will prompt an error cause this translates to:
function createUser(x) {
prop:x
}
With parenthesis, you are still using the default return from the arrow function.
const createUser = (name, email) => ({})
function createUser(name, email) { return {} )

Function declaration of ES6 syntax [duplicate]

This question already has an answer here:
Why doesn't my arrow function return a value?
(1 answer)
Closed 5 years ago.
Suppose we have a function using ES6 syntax like this:
const AccountOverview = (props) => {
const overviewVisible = props.overviewVisible;
const accountNumber = props.accountNumber;
const toggleAccountOverview = props.toggleAccountOverview;
const onClick = (e) => {
e.preventDefault();
toggleAccountOverview(!overviewVisible, accountNumber);
};
// FIXME: eslint WHY??????
/* eslint-disable */
return (
<div
className={props.overviewVisible ? 'acc-block open' : 'acc-block'}
>
<div>
)
}
and a function like this:
const AccountDetails = props => (
<div className="tabInner">
</div>
)
Why the first function is declared using {} and the second function is declared using just ()?
{} means the body of the arrow function, which can contain multiple statements. In this case you need to use return explicitly to return data from your function.
Without {}, your arrow function must have a single statement body which result will be returned implicitly without return statement.
The () is in that situations where you need to return an object within single statement body. Like
const getObject = () => ({ name: 'Test' });
Without () it will consider {} of the object the function body and give you an error.

Define variable and return component from an arrow function

I'd like to define a variable inside a .map() iteration, as well as returning a component.
But having this variable inside the map doesn't work (gives me error). Is this possible at all, and if so how do I do this?
Below is a simplified example of what I'm trying to do:
render() {
return(
<div>
{array.map( (element, index) => (
let disturbingVariable = 100 + index
<MyComponent disturbingVariable={disturbingVariable} />
))}
</div>
)
}
When an arrow function has more than one statement you can no longer use the implicit return syntax.
Add block braces and a return statement:
array.map((element, index) => {
let disturbingVariable = 100 + index
return <MyComponent disturbingVariable={disturbingVariable} />
})
Alternatively, forgo the variable declaration and perform the addition in-place, maintaining the implicit return:
array.map((element, index) =>
<MyComponent disturbingVariable={100 + index} />)
Alternatively, you could omit return and block braces, but the function body should be one liner with implicit return:
render() {
return(
<div>
{array.map((element, index) => <MyComponent disturbingVariable={100 + index}/>)}
</div>
)
}
More about implicit return here
here is an example using jsx component
const App = () => {
const firstName = "abey"
const lastName = "bruck"
return(
<p>hello {`${firstName} ${lastName}`}</p>
)
}
Normally i use arrows when either
It's a single instruction function
I need the this remain referencing to the calling context when the arrow is a callback etc...
However the accepted answer states that
When an arrow function has more than one statement you can no longer
use the implicit return syntax.
which is incorrect because we have the comma (,) operator and you can still use implicit return. Yet, if you need variable declarations you can not do it with var, let or const keywords while using the comma operator. However you can still declare a variable within the arrow function's scope as an unused argument. Let's see how you may do your code without using braces and explicit return.
render() {
return(
<div>
{array.map((e, i, _, disturbingVariable) => (
disturbingVariable = 100 + i, // comma here
<MyComponent disturbingVariable={disturbingVariable} />
))}
</div>
)
}
This is because you are trying to implicitly return value from a function instead of explicitly by using a return statement. If you want to return a value as well as do other operations, you will have to do something like this:-
Notice () converts to {} and use of return statement to explicitly return the component.
render() {
return(
<div>
{array.map( (element, index) => {
let disturbingVariable = 100 + index
return <MyComponent disturbingVariable={disturbingVariable} />
})}
</div>
)
}

React elements and fat arrow functions

In the Redux examples, the syntax used is:
const App = () => (
<div>
<AddTodo />
<VisibleTodoList />
<Footer />
</div>
)
I was toying around with a new example app and mistyped the above code with curly brackets instead of parentheses like so:
const App = () => {
<div>
<AddTodo />
<VisibleTodoList />
<Footer />
</div>
}
I console logged both of the following and the result seemed to be the same. My question is what is the difference between these 2 and why does React like the parentheses but not the curly brackets?
TL;DR
Your first example is more or less equivalent to:
var App = function() { return <div>...</div>; };
Your second is more or less equivalent to:
var App = function() { <div>...</div>; };
React is probably complaining that nothing is being returned in the second example.
Slightly Longer Version
Let's take React out of the equation. In es6 you can create a fat arrow function like this:
const getWord = () => {
return 'unicorn';
}
And we're given a shortcut to do the same thing with less code:
const getWord = () => 'unicorn';
unicorn is returned even though you don't ever explicitly type return anywhere.
In your first example, you wrapped your JSX in parenthesis. The equivalent in our simple example is:
const getWord = () => ('unicorn');
or this
const getWord = () => (
'unicorn'
);
The last four examples are equivalent. Hope that helps!

Categories

Resources