React elements and fat arrow functions - javascript

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!

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" } )

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

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.

Dynamically creating refs without strings

EDIT: We're using React 16.2.0, which is relevant to the question (see this answer).
So far as I can tell, this is the accepted way to create a ref (at least for our version of react):
<div ref={(r) => { this.theRef = r; }}>Hello!</div>
And then it can be used something like this:
componentDidMount() {
if (this.theRef) {
window.addEventListener('scroll', this.handleScroll);
}
}
This works fine. However, if I want to create a dynamically named ref, say as part of a loop, how do I go about naming the ref?
Put in now obsolete terms, I would like something along these lines:
<div ref="{refName}">Hello!</div>
Thanks!
Try just:
<div ref={refName}>Hello!</div>
For a map you need a key, so maybe you could just use that key to map to an object? Like so:
this.myRefs = {}
doSomethingToRef = (key) => {
this.myRefs[key].doSomething()
}
return (
myValues.map(value => (
<div key={value.key} ref = {r => {this.myRefs[value.key] = r}}>{...}</div>
))
)
Use ref like this:
Define the refName inside the class constructor:
this.refName = React.createRef()
Assign the ref in your element:
<div ref={this.refName} id="ref-name">Hello!</div>
To access the refName, use current:
this.refName.current
Example:
if (this.refName.current.id == 'ref-name') {
window.addEventListener('scroll', this.handleScroll);
}
Update
As per your comment, to use ref in older version, you may use just like this:
<div ref={(el) => this.refName = el} id="ref-name">Hello!</div>
{/* notice double quote is not used */}
To access:
this.refs.refName
Example:
if (this.refs.refName.id == 'ref-name') {
window.addEventListener('scroll', this.handleScroll);
}
To do it in more better way, you may use callback pattern.
[short-id][1] might be a good candidate!
It has methods like:
ids.store('foo'); // "8dbd46"
ids.fetch('8dbd46'); // 'foo'
ids.fetch('8dbd46'); // undefined
ids.configure(Object conf)
$ npm install short-id
RefsCmp.js
var shortid = require('shortid');
const RefsList = (newrefs) = > (
{newrefs.map(item => (
<div ref={shortid.generate()}>Hello!</div>
))}
)
export default RefsList;

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>
)
}

ReactJS JSX toString()

I'm writing a documentation website based on React. I want to show the code that is necessary to use a given component from my framework. At the same time I would like to show the actual component running, like a side-by-side view.
Currently, I'm adding the component as a String for the reference implementation and the component as JSX for the running scenario. Something like this:
var ButtonDoc = React.createClass({
render: function () {
let buttonComponent = (
<Button label="Add" />
);
let buttonCode = `<Button label="Add" />`;
return (
<div>
{buttonComponent}
<pre><code>{buttonCode}</code></pre>
</div>
);
}
});
Question: Is there a way that I can get the string representation of the given React component without the need to replicate the code?
I'm expecting something like this:
var ButtonDoc = React.createClass({
render: function () {
let buttonComponent = (
<Button label="Add" />
);
let buttonCode = `${buttonComponent}`;
return (
<div>
{buttonComponent}
<pre><code>{buttonCode}</code></pre>
</div>
);
}
});
The output of the given code is object [object].
As I did not find anything that solved my problem, I ended up creating a npm repository to achieve this task.
https://github.com/alansouzati/jsx-to-string
Usage:
import React from 'react';
import jsxToString from 'jsx-to-string';
let Basic = React.createClass({
render() {
return (
<div />
);
}
}); //this is your react component
console.log(jsxToString(<Basic test1="test" />)); //outputs: <Basic test1="test" />
This is super late but in case anyone read this half a decade later (React v17, Native 0.68), you can also just use curly braces inside of backticks: `${integerToString}`. This will convert your embedded value to string.

Categories

Resources