ReactJS: Cách tạo các component wrapper với props

Các khóa học qua video:
Python SQL Server PHP C# Lập trình C Java HTML5-CSS3-JavaScript
Học trên YouTube <76K/tháng. Đăng ký Hội viên
Viết nhanh hơn - Học tốt hơn
Giải phóng thời gian, khai phóng năng lực

Giới thiệu

Trong bài hướng dẫn này, bạn sẽ tạo các component wrapper với các prop bằng cách sử dụng thư viện JavaScript của ReactComponent wrapper là các component bao quanh các component không xác định và cung cấp cấu trúc mặc định để hiển thị các component con. Mẫu này hữu ích để tạo các phần tử giao diện người dùng (UI) được sử dụng nhiều lần trong suốt một thiết kế, như phương thức, trang mẫu và ô thông tin.

Để tạo các component wrapper, trước tiên bạn sẽ học cách sử dụng các toán tử rest và spread để thu thập các prop không sử dụng để truyền cho các component lồng nhau. Sau đó, bạn sẽ tạo một component sử dụng component có sẵn là children để bọc các component lồng nhau trong JSX như thể chúng là các phần tử HTML. Cuối cùng, bạn sẽ truyền các component như là các prop để tạo các trình bao bọc linh hoạt có thể nhúng JSX tùy chỉnh vào nhiều vị trí trong một component.

Cụ thể trong bài hướng dẫn này, bạn sẽ xây dựng các component để hiển thị danh sách dữ liệu động vật dưới dạng thẻ. Bạn sẽ học cách tách dữ liệu và cấu trúc lại các component khi bạn tạo các component gộp linh hoạt. Đến cuối hướng dẫn này, bạn sẽ có một ứng dụng hoạt động sẽ sử dụng các kỹ thuật prop nâng cao để tạo các component có thể tái sử dụng sẽ mở rộng quy mô và thích ứng khi ứng dụng của bạn phát triển và thay đổi.

Lưu ý : Nếu bạn đã có một dự án làm việc và muốn trực tiếp làm việc với các prop, hãy bắt đầu với Bước 2.

Bước 1 - Tạo một dự án trống

Trước tiên bạn mở terminal ra và tạo một app với câu lệnh sau:

npx create-react-app wrapper-tutorial

Chuyển đến thư mục gốc:

cd wrapper-tutorial

Chạy app:

npm start

Mở file App.js ra rồi chỉnh sửa code để nó chỉ còn chứa nội dung sau:

import './App.css';

function App() {
  return <></>;
}

export default App;

Lưu lại file.

Tiếp theo, bạn mở một terminal mới và xóa file logo.svg đi:

rm src/logo.svg

Tạo một thư mục components trong thư mục src:

mkdir src/components

Tạo thư mục App trong components:

mkdir src/components/App

Di chuyển các file App vào thư mục App:

mv src/App.* src/components/App

Mở file index.js và thay đổi đường dẫn trong import:

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './components/App/App';
import reportWebVitals from './reportWebVitals';

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

Lưu lưu lại và quay lại trang web bạn refresh để chạy, bạn sẽ thấy trang web trống.

Bây giờ dự án đã được thiết lập, bạn có thể tạo component đầu tiên của mình.

Bước 2 - Dùng ...props để thu thập prop không sử dụng

Trong bước này, bạn sẽ tạo một component để hiển thị một tập hợp dữ liệu về một nhóm động vật. Component của bạn sẽ chứa một component lồng để hiển thị một số thông tin một cách trực quan. Để kết nối component cha và component lồng (con), bạn sẽ sử dụng các toán tử rest và spread để truyền các prop không sử dụng từ component cha sang component con mà trong đó cha không cần biết tên hoặc loại prop.

Đến cuối bước này, bạn sẽ có một component cha có thể cung cấp prop cho các component lồng mà không cần phải biết prop là gì. Điều này sẽ giữ cho component cha linh hoạt, cho phép bạn cập nhật component con mà không cần phải thay đổi component cha.

Tạo component AnimalCard

Để bắt đầu, hãy tạo một bộ dữ liệu cho động vật của bạn. Đầu tiên, trong thư mục App hãy tạo một file tên data.js và đưa nào dữ liệu sau:

export default [
  {
    name: 'Lion',
    scientificName: 'Panthero leo',
    size: 140,
    diet: ['meat']
  },
  {
    name: 'Gorilla',
    scientificName: 'Gorilla beringei',
    size: 205,
    diet: ['plants', 'insects']
  },
  {
    name: 'Zebra',
    scientificName: 'Equus quagga',
    size: 322,
    diet: ['plants'],
  }
]

Đây là một mảng các đối tượng động vật trong đó chứa đựng các thông tin gồm tên, tên khoa học, trọng lượng, chế độ ăn uống.

Tiếp theo bạn tạo một thư mục có tên AnimalCard trong thư mục components:

mkdir src/components/AnimalCard

Trong thư mục AnimalCard bạn tạo một component là AnimalCard.js mà sẽ lấy namediet và size như một prop và hiển thị nó:

import PropTypes from 'prop-types';

export default function AnimalCard({ diet, name, size }) {
  return(
    <div>
      <h3>{name}</h3>
      <div>{size}kg</div>
      <div>{diet.join(', ')}.</div>
    </div>
  )
}

AnimalCard.propTypes = {
  diet: PropTypes.arrayOf(PropTypes.string).isRequired,
  name: PropTypes.string.isRequired,
  size: PropTypes.number.isRequired,
}

Ở đây bạn đang destructure các prop trong danh sách tham số cho hàm AnimalCard, sau đó hiển thị các dữ liệu trong một div. Các dữ liệu diet được liệt kê như là một chuỗi duy nhất bằng cách sử dụng phương thức join(). Mỗi phần dữ liệu bao gồm một PropType tương ứng để đảm bảo rằng kiểu dữ liệu là chính xác.

Lưu file lại.

Bây giờ bạn đã có component AnimalCard và dữ liệu của mình, bạn cần kết hợp chúng với nhau. Để làm điều đó, bạn sẽ import các component và các dữ liệu vào component gốc của dự án của bạn: App.js.

Đầu tiên, mở component App.js ra và thêm những phần được đánh dấu như sau:

import './App.css';

import animals from './data';
import AnimalCard from '../AnimalCard/AnimalCard';

function App() {
  return (
    <div className="wrapper">
      {animals.map(animal =>
        <AnimalCard
          diet={animal.diet}
          key={animal.name}
          name={animal.name}
          size={animal.size}
        />
      )}
    </div>
  );
}

export default App;

Lưu file lại.

Khi bạn làm việc trên các dự án phức tạp hơn, dữ liệu của bạn sẽ đến từ những nơi khác nhau hơn, chẳng hạn như APIlocalStorage hoặc các tập tin tĩnh. Tuy nhiên, quá trình sử dụng những cái này sẽ tương tự nhau: gán dữ liệu cho một biến và lặp qua dữ liệu. Trong trường hợp này, dữ liệu là từ một tệp tĩnh, vì vậy bạn đang import trực tiếp vào một biến.

Trong đoạn mã trên, bạn sử dụng phương thức .map() để lặp lại animals và hiển thị các prop. Lưu ý rằng bạn không phải sử dụng từng phần dữ liệu. Ví dụ: bạn không truyền thuộc tính scientificName một cách tường minh. Bạn cũng đang thêm một prop là key mà React sẽ sử dụng để theo dõi dữ liệu được ánh xạ. Cuối cùng, bạn gộp mã vào một div với một className là wrapper mà bạn sẽ sử dụng để thêm một số code CSS.

Để thêm CSS bạn mở file App.css ra và update code để nó chỉ còn chứa code sau:

.wrapper {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    padding: 20px;
}

Đoạn code CSS trên sẽ sử dụng bố cục flexbox để sắp xếp dữ liệu ở dạng hàng. padding cung cấp một số không gian trong cửa sổ trình duyệt và justify-content sẽ trải ra không gian thừa giữa các phần tử.

Lưu file lại và quay lại trình duyệt bạn sẽ nhận được kết quả:

Trình duyệt có dữ liệu cách nhau

Tạo một component chi tiết

Bây giờ bạn đã có một component đơn giản hiển thị dữ liệu. Nhưng giả sử bạn muốn cung cấp cho dữ liệu diet một chút tinh tế bằng cách chuyển đổi văn bản thành biểu tượng cảm xúc (emoji). Bạn có thể thực hiện việc này bằng cách chuyển đổi dữ liệu trong component của mình.

React được thiết kế để linh hoạt, vì vậy khi bạn đang suy nghĩ về cách chuyển đổi dữ liệu, bạn có một số tùy chọn khác nhau như sau:

  • Bạn có thể tạo một hàm bên trong component để chuyển đổi văn bản thành biểu tượng cảm xúc.
  • Bạn có thể tạo một hàm và lưu trữ nó trong một tệp bên ngoài component để bạn có thể sử dụng lại logic trên các component khác nhau.
  • Bạn có thể tạo một component riêng biệt để chuyển đổi văn bản thành biểu tượng cảm xúc.

Mỗi cách tiếp cận đều tốt khi được áp dụng cho đúng trường hợp sử dụng và bạn sẽ thấy mình chuyển đổi giữa chúng khi bạn xây dựng một ứng dụng. Để tránh trừu tượng sớm và phức tạp, bạn nên sử dụng tùy chọn đầu tiên để bắt đầu. Nếu bạn thấy mình muốn sử dụng lại logic, bạn có thể kéo hàm ra khỏi component một cách riêng biệt. Tùy chọn thứ ba là tốt nhất nếu bạn muốn có một phần có thể sử dụng lại bao gồm logic và đánh dấu hoặc bạn muốn tách biệt để sử dụng trên toàn ứng dụng.

Trong trường hợp này, chúng tôi sẽ tạo một component mới, vì chúng tôi sẽ muốn thêm nhiều dữ liệu hơn sau này và chúng tôi đang kết hợp đánh dấu với logic chuyển đổi.

Component mới sẽ được gọi là AnimalDetails. Để thực hiện, hãy tạo một thư mục mới:

mkdir src/components/AnimalDetails

Tiếp theo, bạn tạo một component trong thư mục này với tên là AnimalDetails.js. Bên trong file này ta tạo một thành phần nhỏ hiển thị diet dưới dạng biểu tượng cảm xúc:

import PropTypes from 'prop-types';
import './AnimalDetails.css';

function convertFood(food) {
  switch(food) {
    case 'insects':
      return '🐜';
    case 'meat':
      return '🍖';
    case 'plants':
    default:
      return '🌱';
  }
}

export default function AnimalDetails({ diet }) {
  return(
    <div className="details">
      <h4>Details:</h4>
      <div>
        Diet: {diet.map(food => convertFood(food)).join(' ')}
      </div>
    </div>
  )
}

AnimalDetails.propTypes = {
  diet: PropTypes.arrayOf(PropTypes.string).isRequired,
}

Đối tượng AnimalDetails.propTypes thiết lập hàm để lấy prop diet là một mảng các chuỗi. Sau đó, bên trong component, mã lặp lại diet và chuyển đổi chuỗi thành biểu tượng cảm xúc bằng cách sử dụng câu lệnh switch.

Lưu file lại.

Tiếp theo bạn tạo file AnimalDetails.css và đưa vào một số code CSS như sau:

.details {
    border-top: gray solid 1px;
    margin: 20px 0;
}

Lưu file lại.

Bây giờ bạn đã có một component tùy chỉnh mới, bạn có thể thêm nó vào component AnimalCard của mình.

Bạn mở component AnimalCard.js ra, thay thế câu lệnh diet.join bằng component AnimalDetails mới và truyền diet như là một prop bằng cách thêm các dòng được đánh dấu dưới đây:

import PropTypes from 'prop-types';
import AnimalDetails from '../AnimalDetails/AnimalDetails';

export default function AnimalCard({ diet, name, size }) {
  return(
    <div>
      <h3>{name}</h3>
      <div>{size}kg</div>
      <AnimalDetails
        diet={diet}
      />
    </div>
  )
}

AnimalCard.propTypes = {
  diet: PropTypes.arrayOf(PropTypes.string).isRequired,
  name: PropTypes.string.isRequired,
  size: PropTypes.number.isRequired,
}

Lưu file lại và quay lại trang web bạn sẽ thấy các chi tiết mới.

Trình duyệt với thông tin chi tiết

Truyền thông tin chi tiết thông qua một component với ...props

Các component trong app của bạn hiện tại đang hoạt động tốt với nhau, nhưng có một chút kém hiệu quả trong AnimalCard. Bạn đang rút diet ra khỏi đối số props một cách tường minh, nhưng bạn không sử dụng dữ liệu. Thay vào đó, bạn đang truyền nó qua component. Vốn dĩ không có gì sai về điều này - trên thực tế, bạn sẽ mắc sai lầm khi giao tiếp quá nhiều. Nhưng khi làm điều này, bạn làm cho mã của mình khó bảo trì hơn. Bất cứ khi nào bạn muốn truyền dữ liệu mới đến AnimalDetails, bạn cần cập nhật ba vị trí: App là nơi bạn truyền prop, AnimalDetails là nơi sử dụng prop và AnimalCard là vị trí trung gian.

Có một cách tốt hơn đó là thu thập bất kỳ prop nào không sử dụng bên trong AnimalCard và sau đó truyền trực tiếp những prop đó đến AnimalDetails. Điều này cho bạn cơ hội thực hiện các thay đổi đối với AnimalDetails mà không cần thay đổi AnimalCard. Trên thực tế, AnimalCard không cần biết bất cứ điều gì về prop hay PropTypes, những thứ sẽ diễn ra ở AnimalDetails.

Để làm điều đó, bạn sẽ sử dụng toán tử rest đối tượng. Toán tử này thu thập bất kỳ mục nào không được kéo ra trong quá trình hủy và lưu chúng vào một đối tượng mới.

Đây là một ví dụ đơn giản:

const dog = {
    name: 'dog',
    diet: ['meat']
}

const { name, ...props  } = dog;

Trong trường hợp này, biến name sẽ là 'dog' và biến props sẽ là { diet: ['meat']}.

Để sử dụng một đối tượng làm prop, bạn cần sử dụng toán tử spread là ...props được bao quanh bởi cặp ngoặc xoắn {}. Điều này sẽ thay đổi mỗi cặp key-value thành một prop.

Bạn mở component AnimalCard.js ra. Bạn xóa diet khỏi đối tượng bị hủy và thay vào đó thu thập phần còn lại của các prop vào một biến được gọi props. Sau đó truyền trực tiếp các prop đó đến AnimalDetails:

import PropTypes from 'prop-types';
import AnimalDetails from '../AnimalDetails/AnimalDetails';

export default function AnimalCard({ name, size, ...props }) {
  return(
    <div>
      <h3>{name}</h3>
      <div>{size}kg</div>
      <AnimalDetails
        {...props}
      />
    </div>
  )
}

AnimalCard.propTypes = {
  name: PropTypes.string.isRequired,
  size: PropTypes.number.isRequired,
}

Lưu ý rằng bạn cần phải đặt ...props phía cuối trong danh sách tham số; và bạn có thể xóa diet PropType vì bạn không sử dụng prop đó trong component này.

Trong trường hợp này, bạn chỉ truyền một prop cho AnimalDetails. Trong trường hợp bạn có nhiều prop thì thứ tự sẽ có vấn đề, cụ thể là prop sau sẽ ghi đè lên prop trước đó, vì vậy nếu bạn có một prop mà bạn muốn ưu tiên, hãy đảm bảo rằng nó là điểm cuối cùng. Điều này có thể gây ra một số nhầm lẫn nếu đối tượng props của bạn có một thuộc tính cũng là một giá trị được đặt tên.

Lưu lại và quay lại trang web bạn sẽ thấy trang web không gặp vấn đề gì.

Để xem đối tượng ...props thêm tính linh hoạt như thế nào, hãy truyền scientificName tới AnimalDetails thông qua component AnimalCard.

Đầu tiên, hãy mở component App.js ra, sau đó truyền scientificName như một prop:

import './App.css';

import animals from './data';
import AnimalCard from '../AnimalCard/AnimalCard';

function App() {
  return (
    <div className="wrapper">
      {animals.map(animal =>
        <AnimalCard
          diet={animal.diet}
          key={animal.name}
          name={animal.name}
          size={animal.size}
          scientificName={animal.scientificName}
        />
      )}
    </div>
  );
}

export default App;

Lưu file lại.

Ở đây bạn sẽ thấy rằng bạn sẽ không cần quan tâm đến component AnimalCard, bạn sẽ không cần thực hiện bất kỳ thay đổi nào ở component này.

Tiếp theo, mở AnimalDetails để bạn có thể sử dụng prop mới là scientificName đã được truyền từ App.js:

Prop mới sẽ là một chuỗi mà bạn sẽ thêm vào thẻ <div className="details"> cùng với một dòng khai báo PropType:

...
export default function AnimalDetails({ diet, scientificName }) {
  return(
    <div className="details">
      <h4>Details:</h4>
      <div>
        Scientific Name: {scientificName}.
      </div>
      <div>
        Diet: {diet.map(food => convertFood(food)).join(' ')}
      </div>
    </div>
  )
}

AnimalDetails.propTypes = {
  diet: PropTypes.arrayOf(PropTypes.string).isRequired,
  scientificName: PropTypes.string.isRequired,
}

Lưu file và quay lại trang web bạn sẽ thấy kết quả như sau:

Trình duyệt có tên khoa học

Như vậy trong bước này, bạn đã học cách tạo các prop cha linh hoạt có thể lấy các prop không xác định và truyền chúng vào các thành phần lồng nhau bằng toán tử spread. Đây là một mô hình phổ biến sẽ cung cấp cho bạn sự linh hoạt cần thiết để tạo ra các component có thể phản hồi tập trung. Trong bước tiếp theo, bạn sẽ tạo các component có thể lấy các component không xác định như là các prop bằng cách sử dụng prop được tích hợp sẵn đó là children.

Bước 3 - Tạo các component wrapper với children

Trong bước này, bạn sẽ tạo một component wrapper có thể lấy một nhóm component không xác định như là một prop. Điều này sẽ cung cấp cho bạn khả năng lồng ghép các component như HTML tiêu chuẩn và nó sẽ cung cấp cho bạn một mẫu để tạo các trình wrapper có thể tái sử dụng cho phép bạn tạo ra nhiều component khác nhau cần thiết kế chung nhưng có phần bên trong linh hoạt.

React cung cấp cho bạn một prop có sẵn có tên là children có thể thu thập bất kỳ component con nào. Sử dụng điều này làm cho việc tạo các component wrapper trở nên trực quan và dễ đọc.

Để bắt đầu, hãy tạo một component mới được gọi là Card. Đây sẽ là một component wrapper để tạo ra một style tiêu chuẩn cho bất kỳ component mới nào.

Tạo một thư mục mới có tên Card:

mkdir src/components/Card

Sau đó tạo một component có tên Card.js trong đó lấy children và title làm prop và bao bọc chúng trong một thẻ div bằng cách thêm mã sau:

import PropTypes from 'prop-types';
import './Card.css';

export default function Card({ children, title }) {
  return(
    <div className="card">
      <div className="card-details">
        <h2>{title}</h2>
      </div>
      {children}
    </div>
  )
}

Card.propTypes = {
  children: PropTypes.oneOfType([
    PropTypes.arrayOf(PropTypes.element),
    PropTypes.element.isRequired
  ]),
  title: PropTypes.string.isRequired,
}

Ở đoạn code trên, prop children có thể là một phần tử JSX hoặc một mảng các phần tử JSX. title là một chuỗi.

Lưu file lại.

Tiếp theo, ta thêm một số code CSS. Tạo file Card.css trong thư mục Card rồi đưa đoạn code sau vào:

.card {
    border: black solid 1px;
    margin: 10px;
    padding: 10px;
    width: 200px;
}

.card-details {
    border-bottom: gray solid 1px;
    margin-bottom: 20px;
}

Lưu file lại.

Đến đây ta đã có thêm component Card, và ta sẽ sử dụng nó. Ở đây ta sẽ sử dụng component Card trong AnimalCard.

Mở ra AnimalCard.js ra. Không giống như các prop khác, bạn không truyền children một cách tường minh. Thay vào đó, bạn bao gồm JSX như thể chúng là các phần tử con của HTML. Nói cách khác, bạn chỉ cần lồng chúng vào bên trong phần tử, như sau:

import PropTypes from 'prop-types';
import Card from '../Card/Card';
import AnimalDetails from '../AnimalDetails/AnimalDetails';

export default function AnimalCard({ name, size, ...props }) {
  return(
    <Card title="Animal">
      <h3>{name}</h3>
      <div>{size}kg</div>
      <AnimalDetails
        {...props}
      />
    </Card>
  )
}

AnimalCard.propTypes = {
  name: PropTypes.string.isRequired,
  size: PropTypes.number.isRequired,
}

Ở đoạn code trên bạn thấy, không giống như một component React, bạn không cần phải có một phần tử gốc duy nhất như là một con. Đó là lý do tại sao PropType cho Card được chỉ định, nó có thể là một mảng các phần tử hoặc một phần tử đơn lẻ. Ngoài việc truyền children như là các component lồng nhau, bạn cũng đặt tiêu đề là Animal.

Lưu file lại và quay lại trang web bạn sẽ thấy như sau:

Như vậy, bạn đã có một component Card có thể tái sử dụng và có thể lấy bất kỳ số lượng con lồng nhau nào. Ưu điểm chính của điều này là bạn có thể sử dụng lại Card với bất kỳ component tùy ý nào. Nếu bạn muốn tạo một thẻ Plant, bạn có thể làm điều đó bằng cách gộp thông tin thực vật với component Card. Nó thậm chí không cần phải liên quan gì đến nhau cả: Nếu bạn muốn sử dụng lại component Card trong một ứng dụng hoàn toàn khác có liệt kê những thứ như âm nhạc hoặc dữ liệu tài khoản, bạn cũng có thể làm điều đó. Component Card không quan tâm đến children; bạn chỉ đang sử dụng lại phần tử wrapper, trong trường hợp này là đường viền và tiêu đề được tạo style.

Nhược điểm của việc sử dụng children là bạn chỉ có thể có một thể hiện của prop con. Đôi khi, bạn sẽ muốn một component có JSX tùy chỉnh ở nhiều nơi. May mắn thay, bạn có thể làm điều đó bằng cách truyền các component JSX và React như là  các prop, đây là điều mà ta sẽ đề cập trong bước tiếp theo đây.

Bước 4 - Truyền component như là prop

Trong bước này, bạn sẽ sửa đổi component Card của mình để lấy các component khác làm prop. Điều này sẽ cung cấp cho component của bạn sự linh hoạt tối đa để hiển thị các component không xác định hoặc JSX ở nhiều vị trí trên toàn bộ trang. Không giống như children, bạn chỉ có thể sử dụng một lần, bạn có thể có nhiều component làm prop, mang lại cho component wrapper của bạn khả năng thích ứng với nhiều nhu cầu khác nhau trong khi vẫn duy trì giao diện và cấu trúc chuẩn.

Đến cuối bước này, bạn sẽ có một component có thể wrap (bọc) các component con và cũng hiển thị các component khác trong thẻ. Mẫu này sẽ cung cấp cho bạn sự linh hoạt khi bạn cần tạo các component cần thông tin phức tạp hơn các chuỗi và số nguyên đơn giản.

Hãy sửa đổi component Card để lấy một phần tử React tùy ý được gọi là details.

Đầu tiên, mở component Card.js ra. Tiếp theo, thêm một prop mới gọi là details và đặt nó bên dưới phần tử <h2> như sau:

import PropTypes from 'prop-types';
import './Card.css';

export default function Card({ children, details, title }) {
  return(
    <div className="card">
      <div className="card-details">
        <h2>{title}</h2>
        {details}
      </div>
      {children}
    </div>
  )
}

Card.propTypes = {
  children: PropTypes.oneOfType([
    PropTypes.arrayOf(PropTypes.element),
    PropTypes.element.isRequired
  ]),
  details: PropTypes.element,
  title: PropTypes.string.isRequired,
}

Card.defaultProps = {
  details: null,
}

Prop details này có cùng kiểu với children, nhưng nó cần phải là tùy chọn. Để làm cho nó trở thành tùy chọn, bạn thêm một giá trị mặc định là null. Trong trường hợp này, nếu người dùng không truyền thông tin chi tiết, component sẽ vẫn có giá trị và sẽ không hiển thị thêm bất kỳ thứ gì.

Bây giờ ta thêm một số chi tiết vào component AnimalCard.

Đầu tiên, hãy mở AnimalCard.js ra. Vì component Card đã đang sử dụng children, nên bạn sẽ cần truyền thành phần JSX mới làm prop. Vì đây đều là động vật có vú, hãy thêm nó vào thẻ, nhưng bọc nó trong thẻ <em> để in nghiêng.

...

export default function AnimalCard({ name, size, ...props }) {
  return(
    <Card title="Animal" details={<em>Mammal</em>}>
      <h3>{name}</h3>
      <div>{size}kg</div>
      <AnimalDetails
        {...props}
      />
    </Card>
  )
}
...

Lưu file và quay lại trang web bạn sẽ thấy kết quả như sau:

Trình duyệt với thẻ và thông tin chi tiết

Prop này như vậy nó đã đang rất mạnh mẽ vì nó có thể sử dụng JSX ở bất kỳ kích thước nào. Trong ví dụ này, bạn chỉ thêm một phần tử duy nhất, nhưng bạn có thể chuyển bao nhiêu JSX tùy thích. Nó cũng không cần phải là JSX. Ví dụ: nếu bạn có một phần tử phức tạp, bạn sẽ không muốn truyền nó trực tiếp trong prop thì bạn có thể tạo một component riêng biệt và sau đó truyền component đó như là prop.

Để cụ thể hơn, ta hãy truyền AnimalDetails cho prop details:

...
export default function AnimalCard({ name, size, ...props }) {
  return(
    <Card
      title="Animal"
      details={
        <AnimalDetails
          {...props}
        />
      }
    >
      <h3>{name}</h3>
      <div>{size}kg</div>
    </Card>
  )
}
...

Ở đây bạn sẽ thấy code có vẻ phức tạp hơn một chút.

Lưu file và quay lại trang web bạn sẽ thấy kết quả như sau:

Thẻ có thông tin chi tiết ở trên cùng

Như vậy, đến đây bạn đã có một component Card có thể lấy JSX tùy chỉnh và đặt nó ở nhiều vị trí. Bạn không bị giới hạn ở một prop duy nhất; bạn có thể truyền các phần tử cho bao nhiêu prop tùy thích. Điều này cung cấp cho bạn khả năng tạo các component wrapper linh hoạt có thể mang lại cho các nhà phát triển khác cơ hội tùy chỉnh một component trong khi vẫn giữ được style và chức năng tổng thể của nó.

Truyền component dưới dạng prop không phải là hoàn hảo. Nó khó đọc hơn một chút và không rõ ràng như truyền children, nhưng ngược lại nó rất linh hoạt và bạn có thể sử dụng bao nhiêu tùy ý trong một component. Bạn nên sử dụng children trước, nhưng đừng ngần ngại quay trở lại với prop nếu điều đó là không đủ.

Trong bước này, bạn đã học cách truyền các component JSX và React dưới dạng prop cho một component khác. Điều này sẽ cung cấp cho component của bạn sự linh hoạt để xử lý nhiều tình huống trong đó một component wrapper có thể cần nhiều prop để xử lý JSX hoặc các component.

Phần kết luận

Bạn đã tạo ra nhiều component wrapper có thể hiển thị dữ liệu một cách linh hoạt trong khi vẫn giữ được giao diện và cấu trúc có thể dự đoán được. Bạn đã tạo các component có thể thu thập và truyền các prop không xác định cho các component lồng nhau. Bạn cũng đã sử dụng prop children là prop có sẵn để tạo các component wrapper có thể xử lý một số phần tử lồng nhau tùy ý. Cuối cùng, bạn đã tạo một component có thể lấy các component JSX hoặc React làm prop để component wrapper của bạn có thể xử lý nhiều trường hợp tùy chỉnh khác nhau.

Component wrapper cung cấp cho bạn khả năng thích ứng với các trường hợp không xác định đồng thời tối đa hóa khả năng tái sử dụng và tính nhất quán của mã. Mẫu này hữu ích để tạo các phần tử giao diện người dùng cơ bản mà bạn sẽ sử dụng lại trong toàn bộ ứng dụng bao gồm: nút, cảnh báo, phương thức, trình chiếu, v.v.

» Tiếp: Cách tạo style cho các component React
« Trước: Cách tùy chỉnh component với props
Các khóa học qua video:
Python SQL Server PHP C# Lập trình C Java HTML5-CSS3-JavaScript
Học trên YouTube <76K/tháng. Đăng ký Hội viên
Viết nhanh hơn - Học tốt hơn
Giải phóng thời gian, khai phóng năng lực
Copied !!!