Optimizing React Performance with Stateless Functional Components
Bài đăng này đã không được cập nhật trong 7 năm
React Component
Trong React
, chúng ta xây dựng trang web sử dụng những thành phần (component
) nhỏ và ghép chúng lại. Chúng ta có thể tái sử dụng một component
ở nhiều nơi, với các trạng thái hoặc các thuộc tính khác nhau, trong một component
lại có thể chứa thành phần khác.
Khái niệm component
trong React là một trong những thành phần quan trọng nhất của React. Chúng ta đã biết có ít nhất 3 cách để tạo 1 component
trong React
:
- Sử dụng React.createClass
const React = require('react');
export const Cell = React.createClass({
render() {
const cls = this.props.highlighted ? 'highlight' : '';
return (
<span className={cls} onClick={this.props.userSelected}>
{this.props.value}
</span>
);
}
});
- Sử dụng ES2015 Class Component
import React, { Component } from 'react'
class Cell extends Component {
render() {
const { value, highlighted, userSelected } = this.props;
const cls = highlighted ? 'highlight' : '';
return (
<span className={cls} onClick={event => { userSelected() }}>
{value}
</span>
);
}
}
- Sử dụng Stateless Functional Component
const Cell = ({ value, highlighted, userSelected }) => {
const cls = highlighted ? 'highlight' : '';
return (
<span className={cls} onClick={event => { userSelected() }}>
{value}
</span>
);
}
Ngoài ra, từ Stateless Functional Component
chúng ta có thêm Presentational Component
:
const Cell = ({ value, highlighted, userSelected }) => (
<span className={highlighted ? 'highlight' : ''} onClick={event => { userSelected() }}>
{value}
</span>
);
Optimize Component
Giả sử chúng ta có một mảng 1000 phần tử chứa các con số [1...1000]
.
Chúng ta cần in 1000 số này ra, mỗi số sẽ là 1 Cell
ở trên. Khi click
vào Cell
nào thì Cell
ấy sẽ được highlight
;
import React from 'react';
import Cell from './Cell';
class Board extends React.Component {
constructor(props) {
super(props);
this.state = {
selectedValue: 0,
start: 1,
end: 1000
}
}
cellClickHandler(selectedValue) {
this.setState({selectedValue});
}
render() {
const {start, end, selectedValue} = this.state;
let cells = [];
for (let i = start; i <= end; i++) {
cells.push(
<Cell key={i} value={i} userSelected={this.cellClickHandler} highlighted={i === selectedValue}/>
);
}
return (
<div className='board'>
{cells}
</div>
);
}
}
export default Board;
Khá là đơn giản. Việc set highlight cho 1 Cell
chỉ tác động tới 2 Cell
(1 Cell
đang được highlight và 1 Cell
chuẩn bị được highlight). Tức là chúng ta chỉ cần render
lại cho 2 Cell
này. Tuy nhiên với 4 kiểu định nghĩa Cell
ở trên, chúng ta vẫn phải render
lại 1000 Cell
mỗi lần click
chứ không phải chỉ là 2 Cell
.
May mắn cho chúng ta là React
cung cấp phương thức cho phép chúng ta can thiệp vào quá trình render
lại của 1 component: shouldComponentUpdate(nextProps, nextState)
.
shouldComponentUpdate(nextProps, nextState) {
// Skips render() if returns false
// If shouldComponentUpdate returns false, then render() will be completely skipped until the next state change.
// In addition, componentWillUpdate and componentDidUpdate will not be called.
// Hàm này thực hiện khi state và props thay đổi
// Hàm này sẽ trả về kết quả true/false, bạn sẽ cần sử dụng đến hàm này để xử lý xem có cần update component không
return true;
}
Tuy nhiên không phải lúc nào chúng ta cũng có thể sử dụng shouldComponentUpdate
, chỉ có 2 cách tạo component đầu tiên mới có thể sử dụng được nó, React.createClass
và ES2015 Class
.
shouldComponentUpdate(nextProps) {
return nextProps.value !== this.props.value || nextProps.highlighted !== this.props.highlighted
}
Đối với stateless functional components
chúng ta không thể sử dụng được nó (chính xác hơn là không có để mà dùng).
Note: Từ React 15.3
, chúng ta có thêm 1 kiểu component
nữa, đó chính là PureComponent
.
PureComponent
dựa trên phương thức shouldComponentUpdate
để quyết định xem nó có cần phải render lại component hay không dựa trên việc so sánh this.props
và nextProps
. Tuy nhiên, việc so sánh này chỉ ồn thỏa
khi props
đơn giản, khi props
phức tạp việc so sánh có thể dẫn đến sai sót và component vẫn được render lại.
Stateless Functional Components
Như đã nói ở trên, việc sử dụng stateless functional components
khiến chúng ta không thể can thiệp vào quá trình re-render
của nó bằng việc sử dụng shouldComponentUpdate
. Vậy nếu chúng ta vẫn muốn dùng Stateless Functional Components
và vẫn có thể can thiệp được vào quá trình render của components thì sao?
Một trong các cách có thể giải quyết được vấn đề trên đó chính là sử dụng higher-order components
, tuy nhiên việc này khiến chúng ta phải tạo thêm 1 component
khác cho mỗi stateless components. Khá là mất công. Chúng ta không muốn viết thêm 1 component chỉ wrap
1 component khác. Vậy hãy sử dụng recompose.
Recompose is a React utility belt for function components and higher-order components. Think of it like lodash for React.
Cài đặt recompose
khá là đơn giản
npm install recompose --save
# hoặc
yarn add recompose
recompose
cung cấp cho chúng ta khá nhiều phương thức hay khi xử lý 1 stateless functional component
. Nó cho phép chúng ta tạo ra defaultProps
hay initialState
cho stateless component
và quan trọng hơn nữa là nó cung cấp các phương thức để optimize rendering performance
.
- pure: chức năng tương tự với
PureComponent
đã nói ở trên. - onlyUpdateForKeys: nó chỉ so sánh các
keys
mà chúng ta cung cấp và render lại component khi cáckeys
đó thay đổi giá trị.
import {pure, onlyUpdateForKeys} from 'recompose';
// Cách 1: sử dụng trong quá trình khai báo component
// sử dụng pure
export default const Cell = pure(({ value, highlighted, userSelected }) => (
<span className={highlighted ? 'highlight' : ''} onClick={event => { userSelected() }}>
{value}
</span>
));
// sử dụng onlyUpdateForKeys
const enhance = onlyUpdateForKeys(['value', 'isSelected']);
export default const Cell = enhance(({ value, highlighted, userSelected }) => (
<span className={highlighted ? 'highlight' : ''} onClick={event => { userSelected() }}>
{value}
</span>
));
//Cách 2: Sử dụng sau khi khai báo component
export default pure(Cell);
export default enhance(Cell);
Nguồn tham khảo: https://www.sitepoint.com/optimizing-react-performance-stateless-components/
All rights reserved