I iterate over a list of items and want to call a function onClick(). Example below:
class App extends Component {
state = { items: [1, 2, 3, 4] };
click = i => console.log(i);
render() {
return (
<div>
{this.state.items.map(item => (
<div
key={item}
// this works fine, but I rather not declare functions within the render function / JSX
onClick={() => this.click(item)}
>
{`click on # ${item}`}
</div>
))}
</div>
)
}
}
As you can see, I declare a function in the JSX. I do this over and over, but some time ago I learned that you should avoid declaring a function within the component JSX itself, for performance reasons.
Is this true, also for functional components? And if so, is there any other way to pass dynamic information (item, in this case) to a callback?
NOTE:
I'm looking forward to using hooks at some point, but right now I just want to know a best practice without using them.
NOTE II:
That being said, if you are sure that this is a relevant problem and it could not be solved until now because of hooks, I obviously would like to learn that :)
Is this true, also for functional components?
Well actually there is no functional component used in your code. And everything you do in a function that gets called very often (render() for example) causes performance to decrease, no matter wether that is a function or variable declaration or invokation. Wether that decrease matters is another thing.
And if so, is there any other way to pass dynamic information (item, in this case) to a callback?
You could .bind(...) it:
onClick = {console.log.bind(console, item) }
but really, did you notice any delay on a rerender? Probably not, and if so that is not caused by the function declaration. Write code that looks beautiful to you, don't optimize for the compiler, let the compiler do that.
but some time ago I learned that you should avoid declaring a function within the component JSX itself
You shouldn't really avoid it, rather prefer other ways if possible. In this case there is not really a better way so go with it.
You can declare another method like this. Don't forget to use .bind. Otherwise, the method won't be called correctly.
class App extends Component {
state = { items: [1, 2, 3, 4] };
handleClick(item) {
// do something
console.log(item);
}
render() {
return (
<div>
{this.state.items.map(item => (
<div
key={item}
// this works fine, but I rather not declare functions within the render function / JSX
onClick={this.handleClick.bind(this, item)}
>
{`click on # ${item}`}
</div>
))}
</div>
)
}
}
You can create a parent component which will be responsible for looping through the items and passing the click handler down as a prop to each individual child component.
Then inside the child component you can easily reference the handler as this.props.onClick
Functions (objects) are passed by reference in JavaScript. By declaring it in the parent scope it will only take up space there. If initialized in the child, it will create space in memory for the function with each child component.
class Parent extends Component {
state = { items: [1, 2, 3, 4] };
parentClick(item) {
// do something
console.log(item);
}
render() {
return (
<div>
{this.state.items.map(item => (
<Child item={item} onClick={this.parentClick}>
))}
</div>
)
}
}
class Child extends Component {
childClick(item) {
this.props.onClick(item)
}
render() {
return (
<div>
<p onClick={this.childClick(this.props.item)}>this.props.item</p>
</div>
)
}
}
Related
So I had a question in one of my interviews today that using arrow functions and bind in render is problematic.
Here's some piece of code:
class Component extends React.Component {
constructor(props) {
super(props);
this.state = {
users: [
{ id: 1, name: "Cory" },
{ id: 2, name: "Meg" },
{ id: 3, name: "Bob" }
]
};
}
deleteUser = id => {
this.setState(prevState => {
return {
users: prevState.users.filter(user => user.id !== id)
};
});
};
render() {
return (
<div>
<h1>Users</h1>
<ul>
{this.state.users.map(user => {
return (
<User
key={user.id}
name={user.name}
id={user.id}
onDeleteClick={() => this.deleteUser(user.id)} // Isn't this okay?
/>
);
})}
</ul>
</div>
);
}
}
How is this line of code onDeleteClick={() => this.deleteUser(user.id)} problematic? Don't we usually write functions and methods in a similar fashion.
Any help would be appreciated.
As pointed out by the #keikai in the documentation it states:
Using an arrow function in render creates a new function each time the component renders, which may break optimizations based on strict identity comparison.
It also states that generally it is ok to use arrow functions in the render method but in cases further optimization required, you should not use arrow functions in the render.
Furthermore, using bind in the render method also creates a new function each time the component renders.
Solution:
Bind the function in the constructor(or use an arrow function in the class) and pass it to the prop as a reference and have it called inside the child component appropriately.
In most cases, it's perfectly fine. It's important to understand what's happening there: the anonymous arrow function () => this.deleteUser(user.id) is defined every time that line of code is executed and it uses a bit of RAM.
How expensive is it to define a new anonymous function? It depended on the JavaScript engine but it's usually not much.
Let's extrapolate a little bit: imagine that the users list had a million entries sick. Most probably that single component would bring the browser to a crawl in any machine. But in this ridiculous scenario, there would be many other places for code optimization to consider first - even design optimizations to avoid getting into this situation - and only after applying the most relevant, then worrying about the specific case of onDeleteClick since it has such small impact.
I have the following situation
export default class MyComponent extends Component {
myFunc = dynamicKey => {
// do something with the dynamic key
}
render() {
return (
<Foo>
<button onClick={e => this.myFunc(someDynamicKey1)} />
<button onClick={e => this.myFunc(someDynamicKey2)} />
<button onClick={e => this.myFunc(someDynamicKey3)} />
{/* ... */}
</Foo>
)
}
}
Which is a very common case, but It isn't good because on every render it's creating that arrow function.
So as a walkaround, I made a function that returns another function with that key.
export default class MyComponent extends Component {
myFunc = dynamicKey => e => {
// do something with the dynamic key
}
render() {
return (
<Foo>
<button onClick={this.myFunc(someDynamicKey1)} />
<button onClick={this.myFunc(someDynamicKey2)} />
<button onClick={this.myFunc(someDynamicKey3)} />
{/* ... */}
</Foo>
)
}
}
Now I'm not creating a new function on every render but I'm calling a new function on every render.
Now I'm not sure which one to use. Is calling a function on every render a bad practice? Should I use a arrow function?
When using the curried function, you can use its closure on the current scope.
export default class MyComponent extends Component {
state = {
counter: 42
}
myFunc = dynamicKey => e => {
// closure on the specific this.state.counter value at time of render.
}
}
While returning a new function on every render, its closure is on the recent scope
export default class MyComponent extends Component {
state = {
counter: 42
}
myFunc = dynamicKey => {
// closure on this.state.counter value
}
}
Therefore, it depends on what is the use case.
Ask yourself if the function needs a specific value or the recent one.
Note: if on every render the functions re-declared, it becomes a "difference between function and curried one" question, and for React it doesn't matter as both functions bodies will be executed. So only by memoizing the function (don't call the function with it is called with the same parameters), you can get any noticeable differences.
You can cache your event handlers.
class SomeComponent extends React.Component {
// Each instance of SomeComponent has a cache of click handlers
// that are unique to it.
clickHandlers = {};
// Generate and/or return a click handler,
// given a unique identifier.
getClickHandler = (key) => {
// If no click handler exists for this unique identifier, create one.
if (!this.clickHandlers[key])){
this.clickHandlers[key] = () => alert(key);
}
return this.clickHandlers[key];
}
render() {
return (
<ul>
{this.props.list.map(listItem =>
<li key={listItem.text}>
<Button onClick={this.getClickHandler(listItem.text)} />
</li>
)}
</ul>
);
}
}
see the following article
If you use React hooks then:
const Button = props => {
const onClick = React.useMemo(() => {
alert(listItem.text)
}, [listItem.text]);
}
return <button onClick={onClick}>click</button>
}
If your function does not depend on your component (no this contexts), you can define it outside of the component. All instances of your component will use the same function reference, since the function is identical in all cases.
In contrast to the previous example, createAlertBox remains the same reference to the same location in memory during every render. Button therefore never has to re-render.
While Button is likely a small, quick-to-render component, you may see these inline definitions on large, complex, slow-to-render components, and it can really bog down your React application. It is good practice to simply never define these functions inside the render method.
If your function does depend on your component such that you cannot define it outside the component, you can pass a method of your component as the event handler:
In this case, each instance of SomeComponent has a different alert box. The click event listener for Button needs to be unique to SomeComponent. By passing the createAlertBox method, it does not matter if SomeComponent re-renders. It doesn’t even matter if the message prop changes! The address in memory of createAlertBox does not change, meaning Button does not have to re-render, and you save processing time and improve rendering speed of your application.
For dynamic functions
In this case, you have a variable number of buttons, making a variable number of event listeners, each with a unique function that you cannot possibly know what is when creating your SomeComponent. How can you possible solve this conundrum?
Enter memoization, or what may be easier to refer to as simply, caching. For each unique value, create and cache a function; for all future references to that unique value, return the previously cached function.
I want to know if it's an anti-pattern or if it affects the component somehow to do something like this:
render() {
const MyFuncComponent = ({ prop1, prop2 }) => (
// code here
)
return (
<div>
<MyFuncComponent prop1={something} prop2={else} />
</div>
)
}
Yes, this is an anti-pattern for the same reason we shouldn't use a Higher-Order-Component inside of render.
Don’t Use HOCs Inside the render Method
React’s diffing algorithm (called reconciliation) uses component identity to determine whether it should update the existing subtree or throw it away and mount a new one. If the component returned from render is identical (===) to the component from the previous render, React recursively updates the subtree by diffing it with the new one. If they’re not equal, the previous subtree is unmounted completely.
Normally, you shouldn’t need to think about this. But it matters for HOCs because it means you can’t apply a HOC to a component within the render method of a component:
render() {
// A new version of EnhancedComponent is created on every render
// EnhancedComponent1 !== EnhancedComponent2
const EnhancedComponent = enhance(MyComponent);
// That causes the entire subtree to unmount/remount each time!
return <EnhancedComponent />;
}
The problem here isn’t just about performance — remounting a component causes the state of that component and all of its children to be lost.
This means that the new component will appear in the React tree (which can be explored with the react-devtools) but it won't retain any state and the lifecycle methods like componentDidMount, componentWillUnmount, useEffect will always get called each render cycle.
Solutions
Since there are probably reasons for dynamically creating a component, here are some common patterns that avoid the pitfalls.
Define the new component outside
Either in its own file, or directly above the parent component's definition. Pass any variable as props instead of using the parent component's scope to access the values.
const MyFuncComponent = ({ prop1, prop2 }) => <>{/* code here */}</>;
const MyComponent = props => (
<div>
{props.list.map(({ something, thing }) => (
<MyFuncComponent prop1={something} prop2={thing} />
))}
</div>
);
Helper function
A regular function that returns JSX can be defined and used directly inside another component. It won't appear as a new component inside React's tree, only its result will appear, as if it was inlined.
That way, we can also use variables from the enclosing scope (like props.itemClass in the following example) in addition to any other parameters.
const MyComponent = props => {
// Looks like a component, but only serves as a function.
const renderItem = ({ prop1, prop2 }) => (
<li className={props.itemClass}> {/* <-- param from enclosing scope */}
{prop1} {prop2} {/* other code */}
</li>
);
return <ul>{props.list.map(renderItem)}</ul>;
};
It could also be defined outside the component since it's really flexible.
const renderItem = (itemClass, { prop1, prop2 }) => (
<li className={itemClass}>
{prop1} {prop2} {/* other code */}
</li>
);
const MyComponent = props => (
<ul>
{props.list.map(item => renderItem(props.itemClass, item))}
</ul>
);
But at that point, we should just define a React component instead of faking it with a function. Use React in a predictable manner and to its full potential.
Inline the logic
It's really common to inline JSX inside of a condition or a map callback.
const MyComponent = (props) => (
<ul>
{props.list.map(({ something, thing }) => (
<li className={props.itemClass}>
{something} {thing} {/* other code */}
</li>
))}
</ul>
);
If we find ourselves copy-pasting this same inlined JSX everywhere, it might be time to wrap it up in its own reusable component.
I think in general people avoid defining functions in render but according to this blog post it is not neccesarily a bad practice. The blog post focuses on inline event handler functions being defined in render but I would guess it applies to any function defined in render. Defining functions in render means there is the overhead of redfining them each time render is called but that may not make a noticible performance difference depending on your component.
For the particular example you gave I would reccomend not to define another react component in render. If you do define any functions in render they should be cohesive to what render is doing. Defining another component or adding a bunch of functions inside of render can make in unwieldy and hard to understand what the code is doing.
When I try to modify a base component's variable from a child component. I find that I can only do it by strictly doing the following:
1: Base component must have defined an event handler, strictly a variable onVariableChange event handler, and have it assigned to a local function
2: Base component must have custom attribute variable that will be linked with the above onVariableChange function
3: Child component can now call the this.props.onVariableChange() to make the appropriate modification (from child to base)
in Base declaration:
changeFn(){ //do Something }
Base's render:
return <div> <Child variable={this.stateSomeVar} onVariableChange={this.changeFn} />
in Child:
this.props.onVarChange();
Why is that? Why can't we just call the custom function from child to base directly without the use of custom property?
Am I incorrectly understanding the React's documentation?
in Base:
childFnAnsweredByBase(){
...
}
render(){
return <Child callFromChildFn={this.childFnAnsweredByBase} />
}
REF:
https://reactjs.org/docs/lifting-state-up.html
When I try to modify a base component's variable from a child
component. I find that I can only do it by strictly doing the
following:
I think you mean with variable, base or more accurate parent component's state.
1: Base component must have defined an event handler, strictly a
variable onVariableChange event handler, and have it assigned to a
local function
I don't know what do you mean by saying "strictly", but yes in order to do that parent should have a handler method. The name here is not important, just pass this properly to your child component.
2: Base component must have custom attribute variable that will be
linked with the above onVariableChange function
This variable or state property doesn't need to be linked anywhere and you don't have to pass this to your child component. If child component will use it yes you can pass, but in order to change this in the parent component, it is not needed to be passed to the child.
this.props.onVarChange();
Why is that? Why can't we just call the custom function from child to
base directly without the use of custom property?
If you mean saying by "property" the value itself, again, you don't need to pass it to the child. But, if you mean props, then you should use like that since this function is a part of the child's props.
Here is an example of how you do it without passing the "variable":
const Child = (props) => (
<div>
<input onChange={props.callFromChildFn} />
</div>
);
class App extends React.Component {
state = {
someVar: "initial value",
}
childFnAnsweredByBase = event =>
this.setState({ someVar: event.target.value })
render() {
return (
<div>
<Child callFromChildFn={this.childFnAnsweredByBase} />
<p>someVar is: {this.state.someVar}</p>
</div>
);
}
}
ReactDOM.render(<App />, 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>
Am I incorrectly understanding the React's documentation?
Probably yes. Personally, I don't like that part of the documentation. They are trying to explain an edge case there. Two child components are syncing with some parent's state and show this value with an appropriate situation. Like, one of them shows this value as Fahrenheit and the other one shows it as Celcius. This is why they are passing the state variable (after some conversion) to these components.
In the example above we don't use this state variable in our child component, this is why we don't need it. Here is an example (just a simple, stupid example) showing that how can we use it and why the parent is passing it.
const Child = (props) => {
const { someNum, multiplyTheNumberBy, by } = props;
const handleMultiply = () => {
const newNum = someNum * by;
multiplyTheNumberBy( newNum );
}
return (
<div>
<button onClick={handleMultiply}>Multiply Number By {by}</button>
</div>
);
}
class App extends React.Component {
state = {
someNum: 1,
}
multiplyTheNumberBy = valueFromChild =>
this.setState({ someNum: valueFromChild })
render() {
return (
<div>
<Child
multiplyTheNumberBy={this.multiplyTheNumberBy}
someNum={this.state.someNum}
by={10}
/>
<Child
multiplyTheNumberBy={this.multiplyTheNumberBy}
someNum={this.state.someNum}
by={100}
/>
<p>someNum is: {this.state.someNum}</p>
</div>
);
}
}
ReactDOM.render(<App />, 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>
Update after comments
Also, why do we have to assign const localFn = props.CallFromChildFn ?
why can't we just invoke this.props.CallFromChildFn directly? Or is it
supposed to be props.CallFromChildFn?
First things first. We use this in a class component, so for a functional component, it is not necessary. We can use our props as props.something instead of this.props.something.
Now, the second question is about applying the best practice for performance reasons. For a small app this may not be a problem but for larger apps which has multiple children, components may be problematic.
When defining your functions in a JSX prop, if you use an arrow function and invoke them immediately, or bind it to this there to use it properly, this function is recreated in every render. This is why use references to this functions instead of immediately invoke them somehow or use bind.
Examples.
Think about my first example.
<input onChange={props.callFromChildFn} />
Here, I used the reference of my function and it workes. Since I don't invoke any function here it is not recreated every time when my component renders. I would use it in this way:
<input onChange={e => props.callFromChildFn( e )} />
Here, we are using a callback for onChange as an arrow function. It takes an event and passes it to our callFromChildFn function. This works, too. But, since we used an arrow function here, this function is created in every render.
Let's see my second example.
const { someNum, multiplyTheNumberBy, by } = props;
const handleMultiply = () => {
const newNum = someNum * by;
multiplyTheNumberBy( newNum );
}
return (
<div>
<button onClick={handleMultiply}>Multiply Number By {by}</button>
</div>
Again, instead of using directly my function, I define a handler function here and use its reference. With this newly created function, I can do multiplication operation and use my multiplyTheNumber function from my props and pass it the calculated value. But again, I would use something like this:
const { someNum, multiplyTheNumberBy, by } = props;
return (
<div>
<button onClick={() => multiplyTheNumberBy(someNum * by)}>Multiply Number By {by}</button>
</div>
As you can see, without creating a new function we can use an onClick callback function and use our multiplyTheNumberBy from our props and do the multiplication directly there. But, this function also recreated in every render.
Yes, with the reference method we use a little more code and for small applications maybe this is not necessary. But, I like to use in this way.
I just begun to learn React and JavaScript in general. After I read the documentation and tutorials, I took a look at example projects and try to sort out what I didn't get yet.
And then I saw that there are functions that are defined inside the render()functions, and some that are outside of the render() function.
E.g. for outside of render():
handleClick(e) {
e.preventDefault();
e.target.parentElement.classList.toggle('open');
}
and inside render()...
const divider = (divider, key) => {
const classes = classNames( 'divider', divider.class);
return (<li key={key} className={ classes }></li>);
};
Why do they look so different and why would you like to have some functions inside and some outside of render()?
EDIT:
Another example for a function outside of render():
hideMobile() {
if (document.body.classList.contains('sidebar-mobile-show')) {
document.body.classList.toggle('sidebar-mobile-show')
}
}
EDIT2: In another thread someone answered that, if the logic behind the function is heavy, it should be outside of render(). But why would you like to have function inside render() anyways?
render() is called everytime the state change. So every function that is kept inside render function will be created as a new function each time the state change. Which means that divider will be created newly every time react re-renders.
handleClick is a normal object function.
Functions written inside render function are usually those dealing with rerendering of components.
From example on official site:
First, if we want to build a Clock in the beginning, this how we tried to make a component that is object-oriented, maintainable factor with a stateless function object.
function Clock(props) {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {props.date.toLocaleTimeString()}.</h2>
</div>
);
}
function tick() {
ReactDOM.render(
<Clock date={new Date()} />,
document.getElementById('root')
);
}
setInterval(tick, 1000);
quote from doc
to make the Clock component truly reusable and encapsulated. It will
set up its own timer and update itself every second.
...
Ideally we want to write this once and have the Clock update itself...
So here is the spirit of React, we want to convert this function object to a class, which could maintain itself, so now we involve render() in, more specifically we involve stateful component in:
Add a single empty method to it called render()
...
Clock is now defined as a class rather than a function.
Then we get:
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
this.clockCore = this.clockCore.bind(this);
}
componentDidMount() {
this.timerID = setInterval(
() => this.tick(),
1000
);
}
tick() {
this.setState({
date: new Date()
});
}
clockCore() {
return (<div>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>);
}
render() {
return this.clockCore();
}
}
As you known, render() be triggered again an again if the state of component need to be refreshed by setState().
Update
In my opinion, it's unnecessary to define the function in render().
I have made a little revisions to the original example above to show that.
From example you provided, the usage of divider may be like:
const divider = (divider, key) => {
const classes = classNames( 'divider', divider.class);
return (<li key={key} className={ classes }></li>);
};
return (<ul>{this.state.dividerList?
this.state.dividerList.forEach(divider) : null}</ul>);
I think the reason of this is just for maintainability, someone may want all DOM creating code inside the render() for easy tracing when DOM structure returned is really complicated (and arrow function is lightweight), but as I said it's subjective, it really could be defined outside.
In this kind of case, I used to do below instead, and it seems what you provided is more elegant, but if you defined that function outside of render(), things become distractive to me.
let dividers = [];
if (this.state.dividerList) {
this.state.dividerList.forEach((divider, key) => {
let classes = classNames( 'divider', divider.class);
dividers.push((<li key={key} className={ classes }></li>));
});
}
return (<ul>{dividers}</ul>);
So another function you provided which aims at DOM manipulations feature is totally proper and well to be defined outside.
Besides that, handleClick is a function created and accessible for every Object/Component and divide is a locally scoped function, their functionality can be pretty much the same. However, divider will be created as new function on every render which might have later performance implications, while handleClick is created once for a defined component (Object).