Arrow function should not return assignment? - javascript

My code is working correctly in the app however, my eslint isn't liking it and is saying I should not return assignment. What is wrong with this?
<div ref={(el) => this.myCustomEl = el} />

The Fix:
<div ref={(el) => { this.myCustomEl = el }} />
The Explanation:
Your current code is equivalent to:
<div ref={(el) => { return this.myCustomEl = el }} />
You are returning the result of this.myCustomEl = el. In your code, this is not really a problem -- however, one of the most frustrating bugs in programming occurs when you accidentally use an assignment (=) instead of a comparator (== or ===), for instance:
// This function will always return **true**, surprisingly
function isEqual(a, b) {
// The warning would be thrown here, because you probably meant to type "a===b". The below function will always return true;
return a=b;
}
let k=false;
let j=true;
if(isEqual(k,j)){
// You'll be very, very, very confused as to why this code is reached because you literally just set k to be false and j to be true, so they should be different, right? Right?
thisWillExecuteUnexpectedly();
}
In the above case, the compiler warning makes sense because k=true evaluates to true (as opposed to k===true, which is probably what you meant to type) and causes unintended behavior. Thus, eshint notices when you return an assignment, assumes that you meant to return a comparison, and lets you know that you should be careful.
In your case, you can solve this by simply not returning the result, which is done by adding enclosing brackets {} and no return statement:
<div ref={(el) => { this.myCustomEl = el }} />
You can also adjust the eshint warning like so:
https://eslint.org/docs/rules/no-return-assign

You're implicitly returning an assignment. this.myCustomEl = el is an assignment. You could fix this linting error by changing your arrow function to (el) => { this.myCustomEl =el } which is no longer implicitly returning because you wrapped it in {} instead of ().
Side note: Declaring an arrow function inline inside a render method will break a PureComponent because every time your component renders it has to declare a new anonymous function, so the shallow props comparison that a PureComponent does is broken by this and will always re-render.
Try making that a method of your component.
class MyClass extends React.PureComponent {
getRef = (el) => { this.ref = el; }
render() {
return <div ref={this.getRef} />;
}
}
If the above syntax doesn't work for you, you can use the following:
class MyClass extends React.PureComponent {
constructor(props) {
super(props);
this.ref = null;
this.getRef = this.getRef.bind(this);
}
getRef(el) {
this.ref = el;
}
render() {
return <div ref={this.getRef} />;
}
}

Just wanted to note something I came across. I have Prettier installed and it kept taking away my parens, resulting in eslint error:
To confirm this I added a prettier-ignore:
<div>
{/*prettier-ignore*/}
<Map
ref={(m) => {
this.leafletMap = m;
}}
center={mapCenter}
zoom={zoomLevel}
>
<TileLayer
attribution={stamenTonerAttr}
url={stamenTonerTiles}
/>
</Map>
</div>

Eslint will give us error message if we not applied flowe bracket
Error:
const isNumeric = n => return !isNaN(parseFloat(n)) && isFinite(n)
Solution:
const isNumeric = n => {
return !isNaN(parseFloat(n)) && isFinite(n)
}

Related

Javascript Unexpected use of comma operator no-sequences warning

I have a react library which throw following warning.
Unexpected use of comma operator no-sequences
It indicates the warning happens at 5 row, after (_react.Component) parameter.
exports.default = function (_ref) {
return function () {
var _class, _temp2;
return _temp2 = _class = function () {
}(_react.Component),
_class?.displayName = 'Resizable()', _temp2;
};
}
I simplfied the method. It's actually very long function.
How can i fix the warning? What is the proper syntax?
return a <div> tag to the rendered component e.g;
const App=()=>{ return(<div>
<Header/> <Body/>
</div>
);
}
ReactDom.render(<App/>,document.getElementByid("root));

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.

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

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

how to access vairables outside of map function in js and jsx in a React component

var PieceList = React.createClass({
render: function() {
var pieces;
if (this.props.pieces && this.props.onDeletePiece2) {
var pieces = this.props.pieces.map(function (piece) {
return (
<Piece pieceData={piece} onDeletePiece3={this.props.onDeletePiece2} />
)
});
}
return (
<div className="piecesTable">
{pieces}
</div>
);
}
});
I'm stumped as to how to get this to work. The problem is that {this.props} is not available inside of the map function.
Would a foreach be better here? stumped, pls halp!
map is just a regular JavaScript method (see Array.prototype.map). It can take an argument that sets the context (.map(callback[, thisArg])):
var PieceList = React.createClass({
render: function() {
var pieces;
if (this.props.pieces && this.props.onDeletePiece2) {
var pieces = this.props.pieces.map(function (piece) {
return (
<Piece pieceData={piece} onDeletePiece3={this.props.onDeletePiece2} />
)
}, this); // need to add the context
}
return (
<div className="piecesTable">
{pieces}
</div>
);
}
});
I would suggest going back and reading about this in JavaScript. When you pass an anonymous function to most methods (like .map, .forEach, etc.), it takes the global context (which is almost always window). If you pass in this as the last argument, since that this is referring to the class you just created with React.createClass, it'll set the correct context.
In other words, the way you were trying to do it was access window.props, which obviously doesn't exist. I'd if you opened your console to debug, you'd see the error Object Window doesn't have the property "props" or something very obfuscated.
EDIT 2: React 0.14.x
You can now define stateless functional components for components that do not require complex lifecycle event hooks or internal state
const PieceList = ({pieces, onDeletePiece2}) => {
if (!onDeletePiece2) return;
return (
<div className="piecesTable">
{pieces.map(x => (
<Pieces pieceData={x} onDeletePiece3={onDeletePiece2}>
))}
</div>
);
};
EDIT 1: ES6
As ES6 continues to become more prominent, you can also avoid nitpicky context issues by using an ES6 arrow function.
class PieceList extends React.Component {
renderPiece(piece) {
return <Piece pieceData={piece} onDeletePiece3={this.props.onDeletePiece2} />;
}
render() {
if (!this.props.onDeletePiece2) return;
return (
<div className="piecesTable">
{this.props.pieces.map(piece => this.renderPiece(piece))}
<div>
);
}
}
To get this to run in most environments, you'd need to "transpile" it using something like babel.js
The quick answer is that you need to bind the proper this to the map callback by passing this as the second arg
this.props.pieces.map(..., this);
This might be a better way to write your component tho
var PieceList = React.createClass({
renderPiece: function(piece) {
return <Piece pieceData={piece} onDeletePiece3={this.props.onDeletePiece2} />;
},
render: function() {
if (!this.props.onDeletePiece2) return;
return (
<div className="piecesTable">
{this.props.pieces.map(this.renderPiece, this)}
</div>
);
}
});
Regarding your comment about map
var x = {a: 1, b: 2};
['a', 'b'].map(function(key) {
// `this` is set to `x`
// `key` will be `'a'` for the first iteration
// `key` will be `'b'` for the second iteration
console.log(this[key]);
}, x); // notice we're passing `x` as the second argument to `map`
Will output
// "1"
// "2"
Notice how the second argument to map can set the context for the function. When you call this inside the function, it will be equal to the second variable that was sent to map.
This is JavaScript basics and you should definitely read up more here
Are you using a transpiler -- something like Babel? If so, this code will work fine:
if (this.props.pieces && this.props.onDeletePiece2) {
var pieces = this.props.pieces.map((piece, i) => {
return (
<Piece pieceData={piece} onDeletePiece3={this.props.onDeletePiece2} key={i}/>
)
});
...
If you can't use a transpiler, you could do this:
if (this.props.pieces && this.props.onDeletePiece2) {
var that = this;
var pieces = that.props.pieces.map( function(piece, i) {
return (
<Piece pieceData={piece} onDeletePiece3={that.props.onDeletePiece2} key={i}/>
)
})
...

Categories

Resources