Home >Web Front-end >JS Tutorial >Optimizing React Performance with Stateless Components
This article explores stateless components in React. This type of component does not contain this.state = { ... }
calls, and only processes incoming "props" and child components.
Summary of key points
this.state = { … }
calls. They only handle incoming "props" and subcomponents, which makes them simpler and easier to analyze from a test perspective. shouldComponentUpdate
method that allows for shallow comparisons of each prop. Basics
<code class="language-javascript">import React, { Component } from 'react' class User extends Component { render() { const { name, highlighted, userSelected } = this.props console.log('Hey User is being rendered for', [name, highlighted]) return <div> <h3 style="{{fontStyle:" highlighted : onclick="{event"> { userSelected() }}> {name} </h3> </div> } }</code>
The code runs normally. It's very basic, but it builds examples.
It should be noted:
this.state = { ... }
. console.log
is used to understand its usage. Especially when performing performance optimization, if props are not actually changed, unnecessary re-rendering needs to be avoided. .bind(this)
. Display component
We now realize that the above component is not only stateless, it is actually what Dan Abramov calls a display component. It's just a name, but basically, it's lightweight, produces some HTML/DOM and doesn't handle any state data.
So we can make it into a function! Not only does this feel "cool", it also makes it less terrible because it's easier to understand. It receives input and, independently of the environment, always returns the same output. Of course, it "callback" because one of the props is a callable function.
Let's rewrite it:
<code class="language-javascript">import React, { Component } from 'react' class User extends Component { render() { const { name, highlighted, userSelected } = this.props console.log('Hey User is being rendered for', [name, highlighted]) return <div> <h3 style="{{fontStyle:" highlighted : onclick="{event"> { userSelected() }}> {name} </h3> </div> } }</code>
It feels good, right? It feels like pure JavaScript, you can write it without thinking about the framework you are using.
The problem of continuous re-rendering
Suppose our User component is used in a component that changes state over time. But the state does not affect our components. For example, like this:
<code class="language-javascript">const User = ({ name, highlighted, userSelected }) => { console.log('Hey User is being rendered for', [name, highlighted]) return <div> <h3 style="{{fontStyle:" highlighted : onclick="{event"> { userSelected() }}> {name} </h3> </div> }</code>
Run this code and you will notice that even if nothing changes, our components will be re-rendered! This is not a big problem now, but in practical applications, components tend to become more and more complex, and every unnecessary re-rendering will cause the website to slow down.
If you use react-addons-perf
to debug this application now, I'm sure you will find that time is wasted on rendering Users->User
. Oops! what to do? !
It seems that everything is showing that we need to use shouldComponentUpdate
to cover how React thinks props are different, and we are sure they are not different. In order to add a React lifecycle hook, the component needs to be a class. Alas. So we go back to the original class-based implementation and add a new lifecycle hook method:
Back to class component
<code class="language-javascript">import React, { Component } from 'react' class Users extends Component { constructor(props) { super(props) this.state = { otherData: null, users: [{name: 'John Doe', highlighted: false}] } } async componentDidMount() { try { let response = await fetch('https://api.github.com') let data = await response.json() this.setState({otherData: data}) } catch(err) { throw err } } toggleUserHighlight(user) { this.setState(prevState => ({ users: prevState.users.map(u => { if (u.name === user.name) { u.highlighted = !u.highlighted } return u }) })) } render() { return <div> <h1>Users</h1> { this.state.users.map(user => { return <user name="{user.name}" highlighted="{user.highlighted}" userselected="{()"> { this.toggleUserHighlight(user) }}/> }) } </user> </div> } }</code>
Pay attention to the newly added shouldComponentUpdate
method. This is a bit ugly. Not only can we no longer use functions, but we also have to manually list props that may be changed. This involves a bold assumption that the userSelected
function prop will not change. This is unlikely, but it needs attention.
But please note that even if the included App component is re-rendered, this will only be rendered once! So, this is good for performance. But can we do better?
React.PureComponent
Since React 15.3, there is a new component base class. It's called PureComponent
, and it has a built-in shouldComponentUpdate
method that makes a "shallow comparison" of each prop. marvelous! If we use this we can discard our custom shouldComponentUpdate
method which must list specific props.
<code class="language-javascript">import React, { Component } from 'react' class User extends Component { render() { const { name, highlighted, userSelected } = this.props console.log('Hey User is being rendered for', [name, highlighted]) return <div> <h3 style="{{fontStyle:" highlighted : onclick="{event"> { userSelected() }}> {name} </h3> </div> } }</code>
Try it and you will be disappointed. It re-renders every time. Why? ! The answer is because the userSelected
function is recreated every time in the App's render
method. This means that when a PureComponent
-based component calls its own shouldComponentUpdate()
, it returns true
, because the function is always different, because it is created every time.
Usually, the solution to this problem is to bind the function in the constructor that contains the component. First, if we do this, it means we have to type the method name 5 times (and 1 before):
this.userSelected = this.userSelected.bind(this)
(in the constructor) userSelected() { ... }
(as the method definition itself) <user ... userselected="{this.userSelected}"></user>
(where the rendering of the User component is defined) Another problem is that, as you can see, when the userSelected
method is actually executed, it depends on a closure. In particular, it relies on the scope variable this.state.users.map()
from the iterator. user
method to userSelected
and then when the method is called (in a child component), pass the this
(or its name) go back. Here is a solution like this. user
recompose to rescue!
First, let's review our goals:According to the documentation, recompose is "a library of React utility tools for function components and advanced components. Think of it as a lodash for React."
. There are a lot to explore in this library, but now we want to render our function components without re-rendering when props have not changed. The first time we tried rewriting it back to the function component with recompose.pure, it looks like this:
<code class="language-javascript">import React, { Component } from 'react' class User extends Component { render() { const { name, highlighted, userSelected } = this.props console.log('Hey User is being rendered for', [name, highlighted]) return <div> <h3 style="{{fontStyle:" highlighted : onclick="{event"> { userSelected() }}> {name} </h3> </div> } }</code>
You may notice that if you run this code, the User component will still re-render even if the props (
and keys) have not changed. name
highlighted
Let's go a step further. We don't use
, which is a version of recompose.pure
, but you can specify the prop key you want to focus on: recompose.onlyUpdateForKeys
recompose.pure
<code class="language-javascript">const User = ({ name, highlighted, userSelected }) => { console.log('Hey User is being rendered for', [name, highlighted]) return <div> <h3 style="{{fontStyle:" highlighted : onclick="{event"> { userSelected() }}> {name} </h3> </div> }</code>
After running this code, you will notice that it will only be updated when
or props change. If the parent component is re-rendered, the User component does not. name
highlighted
Long live! We found gold!
First, ask yourself if it's worth optimizing your component performance. Maybe that's more than it's worth it. Your components should be lightweight, maybe you can move any expensive calculations out of the components and move them into external memorable functions, or you can reorganize your components so that some data cannot be No waste of rendering components when used. For example, in this example, you may not want to render the User component before fetch is done. Writing the code in the most convenient way for you, then starting your program and iterating from there to make it perform better is not a bad solution. In this example, in order to improve performance, you need to define the function component from: …changed to… Ideally, rather than showing a way to bypass the problem, the best solution is a new patch from React, which makes a huge improvement to Agree! There is a compromise alternative to having to deal with inline functions that bind methods in the constructor and each recreation. That is the public class field. It is a phase 2 feature in Babel, so your setup will likely support it. For example, here is a branch that uses it, which is not only shorter, but now also means we don't need to list all non-function props manually. This solution must abandon closures. Nevertheless, it is still good to know and realize For more information about React, please check out our course "React The ES6 Way". This article was peer-reviewed by Jack Franklin. Thanks to all SitePoint peer reviewers for making SitePoint’s content perfect! Frequently Asked Questions about Optimizing React Performance with Stateless Components State components (also known as class components) maintain memory about the changes in component state over time. They are responsible for how components behave and render. On the other hand, stateless components (also called functional components) do not have their own state. They receive data from the parent component in the form of props and render it. They are mainly responsible for the UI part of the component. Stateless components can significantly improve the performance of React applications. Since they do not manage their own state or lifecycle methods, they have less code, which makes them easier to understand and test. They can also reduce the amount of memory consumed by the application. To optimize performance, you can convert state components to stateless components as much as possible and use React's Converting a state component to a stateless component includes removing any state or lifecycle method from the component. The component should only receive data through props and render it. Here is an example: // Status component
class Welcome extends React.Component {
render() {
return <code class="language-javascript">import React, { Component } from 'react'
class User extends Component {
render() {
const { name, highlighted, userSelected } = this.props
console.log('Hey User is being rendered for', [name, highlighted])
return <div>
<h3 style="{{fontStyle:" highlighted : onclick="{event"> {
userSelected()
}}>
{name}
</h3>
</div>
}
}</code>
<code class="language-javascript">const User = ({ name, highlighted, userSelected }) => {
console.log('Hey User is being rendered for', [name, highlighted])
return <div>
<h3 style="{{fontStyle:" highlighted : onclick="{event"> {
userSelected()
}}>
{name}
</h3>
</div>
}</code>
shallowEqual
to "automatically" identifying the incoming and comparing is a function, and just because it is not equal does not mean that it is actually different. recompose.onlyUpdateForKeys
when needed.
What is the main difference between a stateful component and a stateless component in React?
How to optimize the performance of my React application using stateless components?
PureComponent
to avoid unnecessary re-rendering. What is PureComponent and how does it help optimize React performance?
PureComponent
is a special React component that helps optimize the performance of your application. It uses shallow prop and state comparison to implement the shouldComponentUpdate
lifecycle method. This means it will re-render only when the state or props change, which can significantly reduce unnecessary re-rendering and improve performance. How to convert a state component in React to a stateless component?
// Stateless Component function Welcome(props) { return
Some best practices for using stateless components in React include: use as many of them as possible to improve performance and readability; keep them small and focus on a single function; and avoid using state or lifecycle methods. It is also recommended to use props deconstruction to write cleaner code.
No, stateless components cannot use lifecycle methods in React. Lifecycle methods are only applicable to class components. However, with the introduction of Hooks in React 16.8, you can now add state and lifecycle features to function components.
While stateless components have many advantages, they also have some limitations. They cannot use lifecycle methods or manage their own state. However, these limitations can be overcome by using React Hooks.
Stateless components improve code readability through simplicity and clarity. They do not manage their own state or use lifecycle methods, which makes them simpler and easier to understand. They also encourage the use of small, reusable components, which can make the code more organized and easier to maintain.
Yes, stateless components can handle events in React. Event handlers can be passed as props to stateless components. Here is an example:
function ActionLink(props) { Return ( Click me ); }
Stateless components promote modularization of code by promoting the use of small, reusable components. Each component can be developed and tested independently, which makes the code easier to maintain and understand. It also encourages separation of concerns, where each component is responsible for a single function.
The above is the detailed content of Optimizing React Performance with Stateless Components. For more information, please follow other related articles on the PHP Chinese website!