Lists và keys trong Reactjs

Lists and keys

Đầu tiên, hãy xem lại cách bạn chuyển đổi lists

Cho đoạn code ở phía dưới, chúng ta sẽ sử dụng hàm map() để lấy mảng numbers và nhân đôi giá trị của chúng. Chúng ta gán mảng mới được trả về bởi map() cho biến doubled và hiển thị nó:

const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map((number) => number * 2);
console.log(doubled);

Đoạn code hiển thị [2,4,6,8,10] ra console.
Trong react, biến đổi mảng thành danh sách phần tử giống như vậy.

Kết xuất nhiều component

Bạn có thể xây dựng những bộ sưu tập các phần tử và đưa chúng vào jsx bằng cách sử dụng {}.

Phía dưới, chúng ta lặp qua mảng numbers sử dụng hàm map(). Chúng ta trả lại phần tử <li> cho mỗi mục. Cuối cùng, chúng ta gán mảng kết quả cho listItems:

const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) =>
  <li>{number}</li>
);

Chúng ta đưa toàn bộ mảng listItems vào trong phần tử <ul>, và kết xuất nó ra DOM:

ReactDOM.render(
  <ul>{listItems}</ul>,
  document.getElementById('root')
);

Đoạn code hiển thị danh sách của các số từ 1 tới 5.

List component cơ bản

thông thường bạn sẽ kết xuất những list bên trong component.
Chúng ta có thể cấu trúc lại ví dụ trước vào trong một component mà nhận một number array và trả về danh sách các phần tử.

function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) =>
    <li>{number}</li>
  );
  return (
    <ul>{listItems}</ul>
  );
}
const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
  <NumberList numbers={numbers} />,
  document.getElementById('root')
);

Khi bạn chạy đoạn code này, bạn sẽ nhận được một cảnh báo rằng một key nên được cung cấp cho các phần tử của danh sách. Một “key” là một thuộc tính chuỗi đặc biệt bạn cần để bao gồm khi tạo danh sách các phần tử. Chúng ta sẽ bàn luận tại sao nó lại quan trọng trong phần kế.

Hãy gán một key cho cá danh sách phần tử vào trong numbers.map() và sửa lỗi thiếu key.

function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) =>
    <li key={number.toString()}>
      {number}
    </li>
  );
  return (
    <ul>{listItems}</ul>
  );
}

const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
  <NumberList numbers={numbers} />,
  document.getElementById('root')
);

Keys

Keys giúp React xác định items nào đã thay đổi, được thêm hoặc xóa. Keys nên được cho vào những phần tử bên trong mảng để cung cấp cho các phần tử một danh tính ổn định.:

const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) =>
  <li key={number.toString()}>
    {number}
  </li>
);

Cách tốt nhất để chọn một key là sử dụng một string mà được xác định duy nhất giữa những anh chị em của nó. Thông thường bạn sẽ sử dụng những ID từ dữ liệu của bạn làm như key:

const todoItems = todos.map((todo) =>
  <li key={todo.id}>
    {todo.text}
  </li>
);

Khi bạn không có những id ổn định cho kết xuất items, bạn có thể sử dụng các chỉ mục của item như một key như một cách cuối cùng:

const todoItems = todos.map((todo, index) =>
  // Only do this if items have no stable IDs
  <li key={index}>
    {todo.text}
  </li>
);

Chúng ta không khuyến khích sử dụng những chỉ mục cho các key nếu thứ tự của item có thể thay đổi. Nó có thể tác động tiêu cực đến hiệu suất và có thể gây ra vấn đề với component state. Nếu bạn không chọn gán một key rõ ràng cho danh sách các item thì react sẽ mặc định sử dụng các chỉ mục làm key.

Trích xuất các component với key

Key chỉ hợp lí trong bối cảnh của các mảng xung quanh.

Ví dụ, nếu bạn trích xuất ListItem Component, bạn nên giữ key trên các phần tử <ListItem> trong mảng chứ không phải trên phần tử trong <ListItem>
Ví dụ : Cách sử dụng key sai:

function ListItem(props) {
  const value = props.value;
  return (
    // Wrong! There is no need to specify the key here:
    <li key={value.toString()}>
      {value}
    </li>
  );
}

function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) =>
    // Wrong! The key should have been specified here:
    <ListItem value={number} />
  );
  return (
    <ul>
      {listItems}
    </ul>
  );
}

const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
  <NumberList numbers={numbers} />,
  document.getElementById('root')
);

Ví dụ: Cách sử dụng key đúng

function ListItem(props) {
  // Correct! There is no need to specify the key here:
  return <li>{props.value}</li>;
}

function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) =>
    // Correct! Key should be specified inside the array.
    <ListItem key={number.toString()}              value={number} />

  );
  return (
    <ul>
      {listItems}
    </ul>
  );
}

const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
  <NumberList numbers={numbers} />,
  document.getElementById('root')
);

Một nguyên tắc nhỏ là các phần tử trong hàm map() cần keys.

Keys phải là duy nhất giữa anh chị em của nó.

Key được sử dụng với array nên được duy nhất giữa các anh chị em của nó. Tuy nhiên chúng không cần là duy nhất trên toàn cục. Chúng ta có thể sử dụng những key giống nhau khi chúng ta tạo ra hai mảng khác nhau:

function Blog(props) {
  const sidebar = (
    <ul>
      {props.posts.map((post) =>
        <li key={post.id}>
          {post.title}
        </li>
      )}
    </ul>
  );
  const content = props.posts.map((post) =>
    <div key={post.id}>
      <h3>{post.title}</h3>
      <p>{post.content}</p>
    </div>
  );
  return (
    <div>
      {sidebar}
      <hr />
      {content}
    </div>
  );
}

const posts = [
  {id: 1, title: 'Hello World', content: 'Welcome to learning React!'},
  {id: 2, title: 'Installation', content: 'You can install React from npm.'}
];
ReactDOM.render(
  <Blog posts={posts} />,
  document.getElementById('root')
);

Keys sử dụng như một gợi ý cho react nhưng chúng không được truyền vào cho component. Nếu bạn cần giá trị giống nhau trong component, vượt qua nó một cách rõ ràng như một thuộc tính với một cái tên khác:

const content = posts.map((post) =>
  <Post
    key={post.id}
    id={post.id}
    title={post.title} />
);

Với ví dụ trên, component Post có thể đọc props.id, nhưng không phải props.key

Nhúng map() trong JSX
Trong ví dụ ở trên chúng ta khai báo một biến listItem tách rời và đưa nó vào JSX:

function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) =>
    <ListItem key={number.toString()}
              value={number} />
  );
  return (
    <ul>
      {listItems}
    </ul>
  );
}

JSX cho phép nhúng bất kỳ biểu thức nào trong dấu ngoặc nhọn nên chúng ta có thể inline kết quả của map():

function NumberList(props) {
  const numbers = props.numbers;
  return (
    <ul>
      {numbers.map((number) =>
        <ListItem key={number.toString()}
                  value={number} />
      )}
    </ul>
  );
}

Thỉnh thoảng kết quả này sẽ dẫn đến code sạch hơn, nhưng kiểu này có thể bị lạm dụng. Như trong js , tùy thuộc vào bạn để quyết định xem có đáng để trích xuất một biến dễ đọc không. Ghi nhớ rằng nếu map() bị lồng nhau, nó có thể là cơ hội để kết xuất một component