Reputation: 4004
I recently read an article about performance optimization in React and i just wanted to make sure i understand one of the key concepts.
Let's say i have this component:
class NewComponent extends React.Component {
render() {
return (
<User>
name={"test"}
</User>
)
}
}
If NewComponent
's state changes, it will not re-render User
, right? Since User
will be the same instance with the same String prop every time.
However, if i write something like this:
class NewComponent extends React.Component {
render() {
return (
<User>
onChange={(value1, value2) => {
// do some stuff
}}
name={"test"}
</User>
)
}
}
User
will always get re-rendered since React is creating and passing a new instance of the onChange
function on every render.
Is that true? When it's just a component, the same instance is being passed, but when there are objects/arrays/functions involved, React creates a new instance on every parent render?
Upvotes: 0
Views: 254
Reputation: 4445
Without using React.memo
for functional components
or PureComponents
for class components
, <User />
will re-render every time <NewComponent />
will receive an updated prop
and/or updates its state
.
As you can see below, even though props
for the <Child />
component don't change, they're still being re-rendered due to the updates in state
of the <Parent />
component.
class Parent extends React.Component {
state = { count: 0 };
updateState = () => {
this.setState(prevState => {
return {
count: prevState.count + 1
};
});
};
render() {
console.log(`Parent.count`, this.state.count);
return (
<div>
<button type="button" onClick={this.updateState}>
Update state
</button>
<Child id="1" />
<Child id="2" />
</div>
);
}
}
function Child(props) {
console.log(`Child ${props.id} re-/rendered!`);
return null;
}
ReactDOM.render(
<Parent />,
document.getElementById("app")
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="app"></div>
If you want to skip re-renders, you could use React.memo
, which according to React
's documentation, "by default it will only shallowly compare complex objects in the props object. If you want control over the comparison, you can also provide a custom comparison function as the second argument." Meaning, if you're passing simple scalar values, such as string
, number
, or boolean
, it will skip the re-render. However, if you have more complex objects, this might not work.
Note below how the complexProp
, for the second button
, causes a re-render, even though it's using React.memo
.
class Parent extends React.Component {
state = { count: 0 };
updateState = () => {
this.setState(prevState => {
return {
count: prevState.count + 1
};
});
};
render() {
console.log(`Parent.count`, this.state.count);
return (
<div>
<button type="button" onClick={this.updateState}>
Update state
</button>
<Child id="1" complexProp={() => { console.log(`I am function!`) }} />
<Child id="2" />
</div>
);
}
}
const Child = React.memo(
function Child(props) {
console.log(`Child ${props.id} re-/rendered!`);
return null
}
)
ReactDOM.render(
<Parent />,
document.getElementById("app")
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="app"></div>
Read more about shallow comparison:
As for your performance question, I'd suggest to be careful with premature optimizations because they could cause performance problems too. If you have visible performance issues that can be measured, then I'd suggest reaching for tools like React.memo
and/or PureComponent
. Otherwise, I would not worry about it, even though your components re-render - it's not always a bad thing.
Here's a good read how premature optimizations
could cause issues:
Performance optimizations are not free. They ALWAYS come with a cost but do NOT always come with a benefit to offset that cost.
Therefore, optimize responsibly.
Upvotes: 1