Chúng ta có component như sau
class ParentComponent extends React.Component {
render() {
return (
<div>
{this.props.items.map(item =>
<ChildComponent {...item} />
)}
</div>
)
}
}
Khi mà ParentComponent
nhận được props.items
, trước hết nó sẽ đổ tất cả dữ liệu vào trong virtual DOM, sau đó kiểm tra xem phần nào của real DOM cần cập nhập, rồi cập nhập toàn bộ trong một lần. Đó là lý do chúng ta bị delay, nó tốn thời gian cho việc tạo ra một số lượng virtual DOM rất lớn trước khi update real DOM, giả dụ có hơn 40.000 dòng dữ liệu, nó đợi tạo 40.000 cái virtual DOM trước khi đẩy hết xuống real DOM.
Chúng ta muốn render ParentComponent
sớm nhất có thể, và sau đó thêm các item từ từ. Chúng ta muốn hiển thị các item vừa có trong virtual DOM, rồi lại render tiếp.
constructor(props) {
super(props);
this.state = {
items: this.props.items.slice(0, 1)
}
}
render() {
return (
//...
{this.state.items.map( item =>
<ChildComponent {...item} />
)}
)
}
Giải pháp ở đây là đưa toàn bộ item
vào trong state
, sau đó render()
theo state.items
. Việc cần làm là update lại state.items
và chèn thêm item một cách từ từ. Với cách này, hàm render
sẽ gọi khá thường xuyên, nhưng được cái nó hiển thị liền
recursive = () => {
setTimeout(() => {
let hasMore = this.state.items.length + 1 < this.props.items.length;
this.setState((prev, props) => ({
items: props.items.slice(0, prev.items.length + 1)
}));
if (hasMore) this.recursive();
}, 0)
}
Hàm đệ quy trên nó sẽ chạy đến khi length bằng nhau. Trên mỗi lần lặp lại nó thêm một element vào mảng state.items
. Dùng setTimeout
để đưa thứ tự ưu tiên của nó xuống thấp nhất.
Nếu thắc mắc tại sao lại gọi hàm setState()
bên trong một hàm đệ quy
- Buộc phải dùng
setState
nếu muốn update real DOM,setState
nó có cách xử lý riêng khi chúng ta gọi nhiều lần - Ví dụ trên đang thêm 1 item một lần gọi, tùy theo nhu cầu, số lượng item có thế nhiều hơn.
setTimeout
có thứ tự ưu tiên chạy cuối cùng, nên, nếu user tương tác với component đã được render, tương tác này sẽ được ưu tiên cao hơn việc render các item còn lại. User có thể bắt đầu tương tác với các item đã render mà không đợi nó show hết- Nếu đã có sẵn toàn bộ các item thì ok, nếu phải đi
fetch
, dùng cách khác - Nếu dùng HOC sẽ không hề làm side effect với cách này
- Bạn cứ test performance để kiểm tra thử nó làm nhanh hay chậm app để xác nhận
Gọi hàm đệ quy trong componentDidMount
componentDidMount() {
this.recursive();
}
Ghi chú
Cách này đã kiểm tra khi render khoảng 10 đến 1500 element, thời gian tốn khoảng 2 đến 3ms.
Nếu muốn tìm một giải pháp của người ta build sẵn thì dùng react-virtualized
Initializing...