Keys trong React 5/5 (3)

Trong React khi chúng ta render nhiều component bằng 1 hàm map, ví dụ:

this.state.users.map((user, i) => <Row user={user} key={i} />)

chúng ta sẽ thấy React thông báo 1 warning trong console như sau: “Warning: Each child in an array or iterator should have a unique “key” prop.” Vậy “key” là gì và tác dụng của chúng là gì ở trong React?

Key là một thuộc tính giúp React xác định item nào được thêm mới, thay đổi hay gỡ bỏ khi chúng ta render nhiều items cùng 1 lúc. Giá trị key nên là duy nhất để phân biệt 1 item với các item khác, thường chúng ta nên lấy id của data truyền vào mỗi item.

this.state.users.map((user) => <Row user={user} key={user.id} />)

hoặc để đơn giản, ta có thể lấy luôn item index để làm key. Tuy nhiên, nếu giá trị của các item thay đổi trong mỗi lần render, thì điều này có thể sẽ gây ra ảnh hưởng xấu đến performance của hệ thống hoặc 1 vài lỗi hơi khó hiểu, nói chung không khuyến khích sử dụng cách này 😀 Ngoài ra không nên sử dụng các hàm như Math.random() để làm key, vì khi ấy key có thể sẽ là duy nhất nhưng sẽ gây rerender lại component rất nhiều lần >> không tốt…

Để tìm hiểu sâu hơn về key, chúng ta sẽ làm 1 ví dụ đơn giản: tạo 1 component Row như sau:

import React, { Component } from 'react';

export default class Row extends React.Component {
  render() {
    return (
      <div>
        {this.props.value}
      </div>
    );
  }
}

trong file app.js, ta sẽ dùng component Row này để render 1 list các số, với key là item index:

import React, { Component } from 'react';
import Row from './Row';

export default class Hello extends Component {
  constructor() {
    super();
    this.state = {
     arr: [5,4,3,2,1],
     lastAddedItem: 5,
    }
  }

  add = () => {
    const item = this.state.lastAddedItem + 1;
    this.setState({
      arr: [item].concat(this.state.arr),
      lastAddedItem: item,
    });
  }

  render() {
    return (
      <div>
        <div>
          {
            this.state.arr.map((value, i) => <Row value={value} key={i} />)
          }
        </div>
        <div onClick={this.add}> 
          Click 
        </div>
      </div>
    );
  }
}

ban đầu React sẽ render ra 1 list component Row như sau:

<Row key="0" value=5>5</Row>
<Row key="1" value=4>4</Row>
<Row key="2" value=3>3</Row>
<Row key="3" value=2>2</Row>
<Row key="4" value=1>1</Row>

sau khi click:

<Row key="0" value=6>6</Row>
<Row key="1" value=5>5</Row>
<Row key="2" value=4>4</Row>
<Row key="3" value=3>3</Row>
<Row key="4" value=2>2</Row>
<Row key="5" value=1>1</Row>

Lúc này React sẽ so sánh key của Row trước và sau khi click, nó sẽ nhận thấy 5 row đầu có key không đổi nhưng props lại thay đổi, vì thế sẽ không khởi tạo component Row mới mà chỉ update props của các Row đã render. Còn Row có key = 5 do chưa có nên sẽ phải khởi tạo mới (trong vòng đời component thì sẽ phải gọi vào componentWillMount), mặc dù value của Row này là 1 đã có từ trước khi click.

Nếu ta thay đổi hàm render trong file app.js, sử dụng key = value, lúc này có trước khi click:

<Row key="5" value=5>5</Row>
<Row key="4" value=4>4</Row>
<Row key="3" value=3>3</Row>
<Row key="2" value=2>2</Row>
<Row key="1" value=1>1</Row>

sau khi click:

<Row key="6" value=6>6</Row>
<Row key="5" value=5>5</Row>
<Row key="4" value=4>4</Row>
<Row key="3" value=3>3</Row>
<Row key="2" value=2>2</Row>
<Row key="1" value=1>1</Row>

Lúc này công việc của React đơn giản hơn rất nhiều, vì các Row có key từ 1 >> 5 không thay đổi, chỉ cần tạo Row có key = 6, ở đây nếu chúng ta sử dụng PureComponent cho component Row thì sẽ thấy sau khi click chỉ có Row với key = 6 là cần render còn các Row khác thì không. Trong khi đó với key = item index như trên, lúc nào 6 Rown cũng phải render lại.

Tạm thời thế đã, nếu nghĩ ra gì hay ho thì mình sẽ bổ sung sau, cảm ơn các bạn!

Please follow and like us:

Please rate this

You May Also Like

About the Author: vietanh

Leave a Reply

Your email address will not be published. Required fields are marked *