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" } )
Related
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.
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 {} )
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.
I am starting to use template literals to make a error generator.
I have working code, but I am forced to declare the list of possible errors inside the constructor scope, and I am not pleased with that.
Is there a way to either copy a template literal without evaluating it so I can evaluate it in the right scope? Or pass the scope to the template literal?
Working error.js:
'use strict';
class Error {
constructor(code) {
const error = {
//...
//API
1001: 'No token',
1002: `${arguments[1]}`,
1003: `${arguments[1]} ! ${arguments[2]}`,
1004: 'Missing data'
//...
};
let i = 0;
this.code = code;
this.error = error[code];
//...
}
}
// export default Error;
module.exports = Error;
Called like:
'use strict';
const Error = require('./error.js');
console.log(new Error(1002, 'var'));
What I would like is to be able to declare const error in the module scope, or better yet, in it's own file that I require. But doing so right now lead to argument not being the ones of the constructor, but the one of the module.
String literals are evaluated immediately. They cannot be used as templates to be formatted later (Unlike for example Python's format strings that look similar).
You could do what Leonid Beschastny suggests and use little functions that does the interpolation for you.
Something like this:
const error = {
1001: () => 'No token',
1002: (args) => `${args[1]}`,
1003: (args) => `${args[1]} ! ${args[2]}`,
1004: () => 'Missing data'
};
this.error = error[code](arguments);
It's a darn shame that template literals aren't more flexible.
Here are two methods that may be close to what you want.
First:
var s = (item, price) => {return `item: ${item}, price: $${price}`}
s('pants', 10) // 'item: pants, price: $10'
s('shirts', 15) // 'item: shirts, price: $15'
To generalify:
var s = (<variable names you want>) => {return `<template with those variables>`}
If you are not running E6, you could also do:
var s = function(<variable names you want>){return `<template with those variables>`}
This seems to be a bit more concise than the previous answers.
https://repl.it/#abalter/reusable-JS-template-literal
Second
class Person
{
constructor (first, last)
{
this.first = first;
this.last = last;
}
sayName ()
{
return `Hi my name is ${this.first} ${this.last}`;
}
}
var bob = new Person("Bob", "Jones")
console.log(bob.sayName()) // Hi my name is Bob Jones
console.log(new Person("Mary", "Smith").sayName()) // Hi my name is Mary Smith
https://repl.it/#abalter/late-evaluation-of-js-template-literal
My preferred solution to pass scope is using this wrapper:
function defer([fisrt, ...rest]) {
return (...values) => rest.reduce((acc, str, i) => acc + values[i] + str, fisrt);
}
That's all. When I want to reuse a template and defer the resolution of the substitutions, I just do:
> t = defer`My template is: ${null} and ${null}`;
> t('simple', 'reusable'); // 'My template is: simple and reusable'
> t('obvious', 'late to the party'; // 'My template is: obvious and late to the party'
> t(null); // 'My template is: null and undefined'
>
> defer`Choose: ${'ignore'} / ${undefined}`(true, false); // 'Choose: true / false'
Applying this tag returns back a 'function' (instead of a 'string') that ignores any parameters passed to the literal. Then it can be called with new parameters later. If a parameter has no corresponding replace, it becomes 'undefined'.
You can find more information in those other answers: this and that.
I am following this tutorial on getting started in ReactJS at https://scotch.io/tutorials/learning-react-getting-started-and-concepts and came across this general code, which has two different parenthesis for return statement.
var MyComponent = React.createClass({
getInitialState: function(){
return {
count: 5
}
},
render: function(){
return (
<h1>{this.state.count}</h1>
)
}
});
Why are they different? Swapping either one of them results an error.
The first is a valid JS return of an object, the second is a grouping operator. Using (stuff && moreStuff) in a return statement will return the result of the code inside the parenthesis, whatever that may be.
In this case there is some special JSX inside the parenthesis which a browser does not understand. This is converted before it's executed, usually at compile time, to a nested tree of react.createElement(...) calls. The JSX is just for convenience to give you an HTML-like experience.
As I said parenthesis just returns the result of what is inside, so you could for example return an object inside it, which is useful when writing short arrow functions: const mergeObject = (obj1, obj2) => ({ ...obj1, ...obj2 }) instead of:
const mergeObject = (obj1, obj2) => {
return {
...obj1,
...obj2,
};
}