I read in an article that if you have some code like:
class Parent extends Component {
render() {
return (
<Child
onClick={() => console.log('You clicked!')}
/>
);
}
}
Child will be re-rendered every time Parent re-renders, even if there's no change in its props, only because the onClick function is inline and so it creates a new reference on every render.
However, even after moving that function outside of render(), Child re-rendered.. so what am i missing here?
In addition, that article also mentioned that inline functions increases a React app's memory footprint, since a new function reference is created on each render. Is that true? Doesn't JS have some sort of automatic garbage collection?
A couple of things, what you have posted only works for Class components, and as to why it works with Class components is that you are creating a callback function and binding it to the instance of the component, therefore each render of the component, it is the same callback function instance being used.
More reading on this https://www.freecodecamp.org/news/this-is-why-we-need-to-bind-event-handlers-in-class-components-in-react-f7ea1a6f93eb/ under "Why don’t we need to bind ‘this’ for Arrow functions?"
For a function component, it's different, there is no class instance, you can use the useCallback hook that will memoize a callback, given a set of dependencies remain the same.
As someone pointed out in the comments you should only really aim to memoize callbacks etc though when they will prevent rerenders of large/deep children
Related
I've been working with react for years and I still have a simple question that I could never understand nor get the answer anywhere. Is calling an outside function in react component body bad?
For example:
import { getUser } from './helpers';
function MyComponent() {
const user = getUser();
return (
...
What will happen to user variable when component gets re-rendered by the parent component? Variables created in component body are created again in memory? Should I use useCallback or useMemo? I feel those two react functions are for other reasons, as expensive calculations and to prevent unecessary prop re-render.
To answer your first question in my experience I've never heard of calling outside functions within a react body as bad. In fact it's always been something that was encouraged especially for helper functions like in your example. There are definitely other ways to handle helper functions that may be needed multiple times (useContext comes to mind) but I don't see anything wrong with importing an outside function to call within a react body.
As far as what happens to user in your example it would get reset to the new return of getUser() upon any component re-render.
The user variable will be set to the value returned by getUser() on each re-render. And yet, getUser() will run on each re-render.
React Hooks are functions with use at the beginning of the function name, documented here.
If declaring an arrow function inside a react class component is bad for performance,
why does declaring variables(arrow functions) inside a functional component have better performance?
The way React is now moving towards using the entire app with only functional components, won't it have performance issues for big apps that have long component trees with lots of variables that being redeclared on each update? (I know some are garbage collected but the declaration still occurs, same as using arrow function inside the render function of a class component)
class ReactComponent extends React.Component {
render() {
return (
<div onClick={() => console.log('do something')}>
<SomeOtherComponent onChange={() => console.log('pass function')} />
</div>
);
}
}
const functionalComponent = () => {
const doSomething = () => console.log('do something');
const passFunction = () => console.log('pass function');
return (
<div onClick={doSomething}>
<SomeOtherComponent onChange={passFunction} />
</div>
);
};
Nothing is "bad for performance", there are only unnecessary computations. If creating a function is necessary to express the behaviour of a program, there is nothing "bad". It is only "bad" if creating the function can be avoided, and it is even worse if a lot of computations can be avoided.
Creating a function is cheap. It creates a new function object, that contains a reference to the functions code as well as to it's environment (the "closure"), so a function expression is not much different than an object literal. Therefore creating functions is not "bad", and it never was.
The real problem that arises from function expressions in React, is not the function expression itself, but the logical result of it:
<div onClick={() => doStuff()}> Test </div>
On every rerender, a new function object gets created, that references a different environment, that might contain a different doStuff method, that might do something different. Therefore on every rerender, React has to detach the listener, and attach a new one referencing the new function, so that the new behaviour gets triggered. For one listener this is cheap, but if you pass down functions to other components, that pass down functions to other components, the cost multiplies (= more components have to rerender), so it might get expensive (= something we might worry about). If the function changes, but what it does does not, reattaching the listeners is uneccessary, and thus it can be avoided by making sure that functions only get recreated when the values they depend on get recreated:
const callback = useCallback(() => doStuff(), [doStuff]); // returns the same function, unless doStuff changes
<div onClick={callback}> Test </div> <- only gets reattached when doStuff changes
If declaring an arrow function inside a react class component is bad for performance
The reason people warn you about creating functions on every render is not because creating functions is slow. It's not; creating functions is very fast.
The performance issue comes when you pass that function to something else, and that something else is using shouldComponentUpdate or PureComponent or React.memo or useMemo or some other form of memoization. Since it received a new function, it thinks it needs to recompute, and so the memoization benefit is lost.
It's true that this issue can occur in function components too, but that's one of the things that useCallback and useMemo are for. You can use those hooks to create the function only once, and thus you will not needlessly break memoization of other components.
I have a parent component which is a flat list which contains a header HeaderComponent. This HeaderComponent is a custom component that I have created which contains 2 child components of its own. Whenever i refresh the list, I am passing a boolean to the HeaderComponent as props which get passed onto its own children, I am doing this so I can check if each component needs to fetch new data or not. The problem is that whenever the parent refreshes and sets a new state the constructors of the child components get called everytime. Shouldn't the constructor be called only the first time the parent initializes and then all further calls involve calling the shouldComponentUpdate method of the children in order to see if it needs an update or not.
Parent component
_renderHeader = () => {
return <HeaderComponent Items={this.state.Data} refresh={this.state.refresh}/>;
};
render() {
console.log("TAG_RENDER render called " + this.state.refresh);
return (
<FlatList
refreshing={this.state.refresh}
onRefresh={() => {
console.log("onRefresh");
this.setState({
refresh: true
}, () => {
this._fetchData();
});
}}
......
ListHeaderComponent={() => this._renderHeader()}
.......
/>
);
}
Header Component
export default class HeaderComponent extends React.Component {
constructor(props) {
super(props);
console.debug("HeaderComponent");
}
render() {
return (
<MainHeader Items={this.props.Items}/>
<SubHeader refresh={this.props.refresh}/>
);
}
}
The constructor of MainHeader and Subheader gets called whenever the parent component refreshes. Does this mean that it is creating new child components each time it refreshes because I can see the render of the children also being called multiple times.
Control your index.js file. If you see <React.StrictMode>, you should change to <>. This is solved my problem.
It should be like:
ReactDOM.render(
<>
<App/>
</>,
document.getElementById('root')
);
As correctly stated in the one of the answers , removing the strict mode fixes the issue. Coming to why it does that, its because the strict mode intentionally calls the 'render' method twice in order to detect potential problems.
React works in two phases:render and commit. Render phase checks and determines the new changes to be applied. And commit phase applies it.
Render phase lifecycle includes methods like : constructor, UNSAFE_componentWillMount,UNSAFE_componentWillReceiveProps, ...,render and few more.
The render phase is time consuming and is often broken into pieces to free up the browser. Render phase might be called multiple times before the commit phase(usually very fast).
Since the render phase methods are called more than once, its important that none of those method have any problems or side effects.
Thus just in order to highlight the possible side effects to make them easy to spot, react explicitly double invoke the render phase methods.
You can read more about this on :https://reactjs.org/docs/strict-mode.html#detecting-unexpected-side-effects :)
Strict mode can’t automatically detect side effects for you, but it can help you spot them by making them a little more deterministic. This is done by intentionally double-invoking the following functions:
Class component constructor, render, and shouldComponentUpdate
methods
Class component static getDerivedStateFromProps method
Function component bodies
State updater functions (the first argument to setState)
Functions passed to useState, useMemo, or useReducer
https://reactjs.org/docs/strict-mode.html
As stated in the site,
Note:
This only applies to development mode. Lifecycles will not be double-invoked in production mode.
I am developing a web page using React, and have some questions about the "Lifting Stat Up" example (and I paste the link for complete code of it here for quick reference), which is inconsistent with what I encountered in my own project.
My question is about this part:
<TemperatureInput
scale="c"
temperature={celsius}
onTemperatureChange={this.handleCelsiusChange} />
while user input new values, the celsius will be re-calculated (triggered by a callback function in TemperatureInput which calls handleCelsiusChange, and then render is triggered), and passed as one of props to TemperatureInput. But inside the definition of TemperatureInput, why componentWillReceiveProps is not defined? In my practice, if the props is assigned in constructor only, it will not be updated automatically if value changed. As the document said, it will not create a new element but just update the existing one for performance. If there is no new instance is created, the constructor would not be invoked, so the this.props will not be updated without a componentWillReceiveProps function.
All these above is consistent to my practice, but not to the example. Why componentWillReceiveProps is not required in the example to make this.props updated?
The constructor in this case is not doing anything special with the props, it is just calling the React.Component constructor with super() which is what it would do anyway. If it was setting some state from props for example, then you would need a componentWillReceiveProps, as you would need to update the state when the props change.
When the component gets new props, the constructor is not invoked again, as it is already an instance, instead react updates the props on the component instance, and calls the render() again, so the props in render() will be the updated props. If you had a componentWillReceiveProps defined, it will be called before the call to render();
I'm confused with these words :
if this callback is passed as a prop to lower components, those components might do an extra re-rendering
The key part is where it says that a problem with it is that a callback is created every time the LoggingButton renders.
Say a child component was created like:
MyButton onClick={ (e) => this.handleClick.bind(this)}
I'm that case if LoggingButton rerenders, MyButton will render too becasue the reference to this.handleClick that was created anonymously will be destroyed.
Alternatively if the function is bound in the constructor the reference will not be destroyed if Logging Button rerenders so MyButton will not render again.
Where you really dont want to do the arrow function is in a loop.