Why shouldn't JSX props use arrow functions or bind?
Why you shouldn't use inline arrow functions in JSX props
Using arrow functions or binding in JSX is a bad practice that hurts performance, because the function is recreated on each render.
Whenever a function is created, the previous function is garbage collected. Rerendering many elements might create jank in animations.
Using an inline arrow function will cause
PureComponent
s, and components that useshallowCompare
in theshouldComponentUpdate
method to rerender anyway. Since the arrow function prop is recreated each time, the shallow compare will identify it as a change to a prop, and the component will rerender.
As you can see in the following 2 examples - when we use inline arrow function, the <Button>
component is rerendered each time (the console shows the 'render button' text).
Example 1 - PureComponent without inline handler
class Button extends React.PureComponent { render() { const { onClick } = this.props; console.log('render button'); return ( <button onClick={ onClick }>Click</button> ); }}
class Parent extends React.Component { state = { counter: 0 } onClick = () => this.setState((prevState) => ({ counter: prevState.counter + 1 })); render() { const { counter } = this.state; return ( <div> <Button onClick={ this.onClick } /> <div>{ counter }</div> </div> ); }}
ReactDOM.render( <Parent />, document.getElementById('root'));
<script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script><script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script><div id="root"></div>
JSX props should not use arrow functions eslint warning
The problem with your code is that you're passing a callback as a property directly. You could declare it as a wrapper using useCallback
before passing it down to the component, like so:
const doSmthHandlerWrapper = useCallback(
() => doSmthHandler(id),
[id]
)
<ComponentB>
doSmth={doSmthHandlerWrapper}
</ComponentB>
setState and JSX props should not use arrow functions
You can set id or name of an element same with the name of a state variable. So you can create one function and pass it to all inputs like:
onFieldChange = (e) => {
const key = e.target.id
const value = e.target.value
this.setState({[key]:value})
}
Bind vs Arrow Function when passing onChange props (React)
Since it is only using a reference to the function, we are not causing a re-render each time
You're wrong.
The bind
method returns a new function (so will trigger a re-render).
To avoid re-renders, make use of the useCallback
hook.
Or, since you don't appear to be making use of this
inside myFunction
(otherwise () => myFunction()
would break it), just pass myFunction
itself without creating a new function.
onClick={myFunction}
No .bind() or Arrow Functions in JSX Props making no sense to me when I need to pass arguments
Either using bind and arrow functions, will create a new function passing a completely new prop to your component, causing unnecessary rerenders and extra work for the garbage collector, using data-attributes is a bad design and is not the React way of doing things, you should not access the DOM directly, but rather let React handle things. Instead of that you can just make a new component and pass the the handler as a prop, handling the "binding" of the id in a method of the component:
class User extends Component {
handleClick() {
this.props.handleToggleActive(this.props.user.id);
}
render() {
return (
<li>
<Link to={`/users/${this.props.user.id}`}>{this.props.user.name}</Link>
<Button onClick={this.handleClick}>Toggle Active</Button>
</li>
)
}
}
export class UserList extends Component {
constructor(props) {
super(props);
this.handleToggleActive = this.handleToggleActive.bind(this);
}
handleToggleActive(userId) {
console.log(userId);
}
render() {
return (
<ul className="user-list">
{this
.props
.users
.map(user => (
<User key={user.id} user={user} handleToggleActive={this.handleToggleActive} />
))}
</ul>
);
}
}
React/ ESLint - JSX props should not use arrow functions
You can refactor button into its own component:
class MyButton extends Component {
static propTypes = {
language: PropTypes.string.isRequired,
};
onClick = () => console.log(this.props.language);
render() {
const {language} = this.props;
return (
<button onClick={this.onClick} type="submit">
{language}
</button>);
}
}
and then in your LanguageDropDown class, use MyButton like this:
class LanguageDropdown extends Component {
...
render() {
return (
<div>
{this.props.languages.map(lang => <MyButton key={lang} language={lang}/>)}
</div>
)
}
...
}
A couple of additional things:
- You have a typo onCLick should be onClick
- You need a key for repeated items
Formik throwing Error: JSX props should not use functions in React
<Field name='name' validate={() => validateFunc}>
{({ field, form }) => (
<FormControl isInvalid={form.errors.name && form.touched.name}>
<FormLabel htmlFor='name'>Default</FormLabel>
<Input {...field} id='name' placeholder='name' />
<FormErrorMessage>{form.errors.name}</FormErrorMessage>
</FormControl>
)}
</Field>
maybe you can try this to fix your problem
Related Topics
How to Access Iframe Elements with JavaScript
Interface Type Check with Typescript
Get the Element with the Highest Occurrence in an Array
How to Make a Promise from Settimeout
Event Handlers Inside a JavaScript Loop - Need a Closure
How to Get Element by Class Name
When Should I Use Jquery's Document.Ready Function
Javascript: Inline Script with Src Attribute
Phantomjs Not Waiting for "Full" Page Load
How to Hide JavaScript Code in a Webpage
Why Doesn't Equality Check Work with Arrays
Jquery .Ready in a Dynamically Inserted Iframe
How to Share $Scope Data Between States in Angularjs Ui-Router
Getting Around X-Frame-Options Deny in a Chrome Extension
Get Global Variable Dynamically by Name String in JavaScript
Are Trailing Commas in Arrays and Objects Part of the Spec