Cách tạo các thành phần Wrapper trong React với Props
Trong hướng dẫn này, bạn sẽ tạo các thành phần shell bọc với các đạo cụ bằng cách sử dụng thư viện JavaScript của React . Các thành phần bao bọc là các thành phần bao quanh các thành phần chưa biết và cung cấp một cấu trúc mặc định để hiển thị các thành phần con. Mẫu này hữu ích để tạo các phần tử giao diện user (UI) được sử dụng lặp đi lặp lại trong suốt một thiết kế, như phương thức, trang mẫu và ô thông tin. Để tạo các thành phần shell bọc, trước tiên bạn sẽ học cách sử dụng các toán tử còn lại và dàn trải để thu thập các đạo cụ không sử dụng để chuyển cho các thành phần lồng nhau. Sau đó, bạn sẽ tạo ra một thành phần có sử dụng được xây dựng trong children
thành phần để quấn thành phần lồng nhau trong JSX như thể chúng là HTML yếu tố. Cuối cùng, bạn sẽ chuyển các thành phần làm đạo cụ để tạo các shell bọc linh hoạt có thể nhúng JSX tùy chỉnh vào nhiều vị trí trong một thành phần.
Trong phần hướng dẫn này, bạn sẽ xây dựng các thành phần để 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 thành phần khi bạn tạo các thành phần gói 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 nâng cao để tạo ra các thành phần có thể tái sử dụng sẽ mở rộng và thích ứng khi ứng dụng của bạn phát triển và thay đổi.
Lưu ý : Bước đầu tiên cài đặt một dự án trống mà bạn sẽ xây dựng bài tập hướng dẫn. 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 đạo cụ, hãy bắt đầu với Bước 2 .
Yêu cầu
Bạn cần một môi trường phát triển chạy Node.js ; hướng dẫn này đã được thử nghiệm trên Node.js version 10.20.1 và npm version 6.14.4. Để cài đặt phần mềm này trên macOS hoặc Ubuntu 18.04, hãy làm theo các bước trong Cách cài đặt Node.js và Tạo Môi trường Phát triển Cục bộ trên macOS hoặc phần Cài đặt Sử dụng PPA của Cách Cài đặt Node.js trên Ubuntu 18.04 .
Trong hướng dẫn này, bạn sẽ tạo một ứng dụng với Create React App . Bạn có thể tìm thấy hướng dẫn cài đặt ứng dụng với Tạo ứng dụng React và thông tin chung về cách hoạt động của ứng dụng này tại Cách cài đặt dự án phản ứng với Tạo ứng dụng React .
Bạn sẽ sử dụng các thành phần React, bạn có thể tìm hiểu về điều này trong hướng dẫnCách tạo các thành phần tùy chỉnh trong React của ta . Nó cũng sẽ giúp bạn hiểu cơ bản về các đạo cụ React, bạn có thể tìm hiểu về cách tùy chỉnh các thành phần React với các đạo cụ .
Bạn cũng cần kiến thức cơ bản về JavaScript, bạn có thể tìm thấy kiến thức này trong loạt bài Cách viết mã trong JavaScript của ta , cùng với kiến thức cơ bản về HTML và CSS. Một nguồn tốt cho HTML và CSS là Mạng nhà phát triển Mozilla .
Bước 1 - Tạo một dự án trống
Trong bước này, bạn sẽ tạo một dự án mới bằng Tạo ứng dụng React . Sau đó, bạn sẽ xóa dự án mẫu và các file liên quan được cài đặt khi bạn khởi động dự án. Cuối cùng, bạn sẽ tạo một cấu trúc file đơn giản để tổ chức các thành phần của bạn .Điều này sẽ cung cấp cho bạn cơ sở vững chắc để xây dựng ứng dụng shell bọc của hướng dẫn này trong bước tiếp theo.
Để bắt đầu, hãy tạo một dự án mới. Trong dòng lệnh của bạn, hãy chạy tập lệnh sau để cài đặt một dự án mới bằng cách sử dụng create-react-app
:
- npx create-react-app wrapper-tutorial
Sau khi dự án kết thúc, hãy thay đổi vào folder :
- cd wrapper-tutorial
Trong cửa sổ hoặc tab terminal mới, hãy bắt đầu dự án bằng cách sử dụng tập lệnh bắt đầu Tạo ứng dụng React . Trình duyệt sẽ tự động làm mới các thay đổi, vì vậy hãy để tập lệnh này chạy trong khi bạn làm việc:
- npm start
Bạn sẽ nhận được một server local đang chạy. Nếu dự án không mở trong cửa sổ trình duyệt, bạn có thể mở bằng http://localhost:3000/
. Nếu bạn đang chạy điều này từ một server từ xa, địa chỉ sẽ là http:// your_domain :3000
.
Trình duyệt của bạn sẽ tải với một ứng dụng React đơn giản được bao gồm như một phần của Create React App:
Bạn sẽ xây dựng một tập hợp các thành phần tùy chỉnh hoàn toàn mới, vì vậy bạn cần bắt đầu bằng cách xóa một số mã soạn sẵn để bạn có thể có một dự án trống.
Để bắt đầu, hãy mở src/App.js
trong editor . Đây là thành phần root được đưa vào trang. Tất cả các thành phần sẽ bắt đầu từ đây. Bạn có thể tìm thêm thông tin về App.js
tại Cách cài đặt một dự án React với Tạo ứng dụng React .
Mở src/App.js
bằng lệnh sau:
- nano src/App.js
Bạn sẽ thấy một file như thế này:
import React from 'react'; import logo from './logo.svg'; import './App.css'; function App() { return ( <div className="App"> <header className="App-header"> <img src={logo} className="App-logo" alt="logo" /> <p> Edit <code>src/App.js</code> and save to reload. </p> <a className="App-link" href="https://reactjs.org" target="_blank" rel="noopener noreferrer" > Learn React </a> </header> </div> ); } export default App;
Xóa import logo from './logo.svg';
dòng import logo from './logo.svg';
. Sau đó, thay thế mọi thứ trong câu lệnh return
để trả về một tập hợp các thẻ trống: <></>
. Điều này sẽ cung cấp cho bạn một trang hợp lệ mà không trả lại gì. Mã cuối cùng sẽ giống như sau:
import React from 'react'; import './App.css'; function App() { return <></>; } export default App;
Lưu và thoát khỏi editor .
Cuối cùng, xóa logo. Bạn sẽ không sử dụng nó trong ứng dụng của bạn và bạn nên xóa các file không sử dụng khi làm việc. Nó sẽ giúp bạn khỏi nhầm lẫn về lâu dài.
Trong cửa sổ terminal , nhập lệnh sau:
- rm src/logo.svg
Nếu bạn nhìn vào trình duyệt của bạn , bạn sẽ thấy một màn hình trống.
Đến đây bạn đã hoàn thành dự án Tạo ứng dụng React mẫu, hãy tạo một cấu trúc file đơn giản. Điều này sẽ giúp bạn giữ cho các thành phần của bạn bị cô lập và độc lập.
Tạo một folder được gọi là components
trong folder src
. Điều này sẽ chứa tất cả các thành phần tùy chỉnh của bạn.
- mkdir src/components
Mỗi thành phần sẽ có folder riêng để lưu trữ file thành phần cùng với các kiểu, hình ảnh nếu có và các bài kiểm tra.
Tạo folder cho App
:
- mkdir src/components/App
Di chuyển tất cả các file App
vào folder đó. Sử dụng ký tự đại diện, *
, để chọn các file nào bắt đầu bằng App.
dù phần mở rộng file . Sau đó, sử dụng lệnh mv
để đưa chúng vào folder mới:
- mv src/App.* src/components/App
Tiếp theo, cập nhật đường dẫn nhập tương đối trong index.js
, là thành phần root khởi động toàn bộ quá trình:
- nano src/index.js
Câu lệnh nhập cần trỏ đến file App.js
trong folder App
, vì vậy hãy thực hiện thay đổi được đánh dấu sau:
import React from 'react'; import ReactDOM from 'react-dom'; import './index.css'; import App from './components/App/App'; import * as serviceWorker from './serviceWorker'; ReactDOM.render( <React.StrictMode> <App /> </React.StrictMode>, document.getElementById('root') ); // If you want your app to work offline and load faster, you can change // unregister() to register() below. Note this comes with some pitfalls. // Learn more about service workers: https://bit.ly/CRA-PWA serviceWorker.unregister();
Lưu và thoát khỏi file .
Bây giờ dự án đã được cài đặt , bạn có thể tạo thành phần đầu tiên của bạn .
Bước 2 - Thu thập đạo cụ không sử dụng với ...props
Trong bước này, bạn sẽ tạo một thành phần để hiển thị một tập hợp dữ liệu về một group động vật. Thành phần của bạn sẽ chứa một thành phần lồng nhau thứ hai để hiển thị một số thông tin một cách trực quan. Để kết nối thành phần cha và thành phần lồng nhau, bạn sẽ sử dụng các toán tử còn lại và dàn trải để chuyển các đạo cụ không sử dụng từ cha mẹ sang con mà không cần cha mẹ biết tên hoặc loại đạo cụ.
Đến cuối bước này, bạn sẽ có một thành phần mẹ có thể cung cấp đạo cụ cho các thành phần lồng nhau mà không cần phải biết đạo cụ là gì. Điều này sẽ giữ cho thành phần cha linh hoạt, cho phép bạn cập nhật thành phần con mà không cần phải thay đổi thành phần cha.
Tạo thành phần AnimalCard
Để bắt đầu, hãy tạo một bộ dữ liệu cho động vật của bạn. Trước tiên, hãy mở một file có chứa tập dữ liệu trong folder components/App
:
- nano src/components/App/data.js
Thêm 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'], } ]
Danh sách động vật này là một loạt các đối tượng bao gồm tên động vật, tên khoa học, trọng lượng và chế độ ăn.
Lưu và đóng file .
Tiếp theo, tạo một folder cho thành phần AnimalCard
:
- mkdir src/components/AnimalCard
Mở một file mới trong directo:
- nano src/components/AnimalCard/AnimalCard.js
Bây giờ, hãy thêm một thành phần sẽ lấy name
, diet
và size
làm chỗ dựa và hiển thị nó:
import React from 'react'; 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 destructuring các đạo cụ trong danh sách tham số cho AnimalCard
chức năng, sau đó hiển thị các dữ liệu trong một div
. Dữ liệu về diet
được liệt kê dưới dạng một chuỗi đơn 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 và đóng file .
Đến đây bạn đã có thành phần và dữ liệu của bạn , bạn cần kết hợp chúng với nhau. Để làm điều đó, hãy nhập thành phần và dữ liệu vào thành phần root của dự án của bạn: App.js
Đầu tiên, mở thành phần:
- nano src/components/App/App.js
Từ đó, bạn có thể lặp lại dữ liệu và trả về một AnimalCard
mới với các đạo cụ có liên quan. Thêm các dòng được đánh dấu vào App.js
:
import React from 'react'; 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 và đóng file .
Khi bạn làm việc trên các dự án phức tạp hơn, dữ liệu sẽ đến từ nhiều nơi khác nhau, chẳng hạn như API , localStorage
hoặc file tĩnh. Nhưng quy trình sử dụng từ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 file tĩnh, vì vậy bạn đang nhập trực tiếp vào một biến.
Trong đoạn mã này, bạn sử dụng phương thức .map()
để lặp lại các animals
và hiển thị các đạo cụ. Lưu ý bạn không phải sử dụng từng phần dữ liệu. Bạn chưa đi qua một cách rõ ràng scientificName
tài sản, ví dụ. Bạn cũng đang thêm một key
riêng mà React sẽ sử dụng để theo dõi dữ liệu được ánh xạ . Cuối cùng, bạn đang gói mã bằng một div
với className
của wrapper
mà bạn sẽ sử dụng để thêm một số kiểu.
Để thêm kiểu này, hãy mở App.css
:
- nano src/components/App/App.css
Loại bỏ kiểu dáng bảng mẫu và thêm thuộc tính flex vào một lớp được gọi là wrapper
:
.wrapper { display: flex; flex-wrap: wrap; justify-content: space-between; padding: 20px; }
Điều này sẽ sử dụng bố cục flexbox để tổ chức dữ liệu để nó sẽ thành dòng. padding
cung cấp một số không gian trong cửa sổ trình duyệt và justify-content
trải ra khoảng trống thừa giữa các phần tử.
Lưu và thoát khỏi file . Khi bạn làm như vậy, trình duyệt sẽ làm mới và bạn sẽ thấy một số dữ liệu được tách ra.
Tạo một thành phần chi tiết
Đến đây bạn có một thành phần đơ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. Bạn có thể làm điều này bằng cách chuyển đổi dữ liệu trong thành phần của bạn .
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:
- Bạn có thể tạo một hàm bên trong thành phần để 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 file bên ngoài thành phần để bạn có thể sử dụng lại logic trên các thành phần khác nhau.
- Bạn có thể tạo một thành phần 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 thành phần 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, ta sẽ tạo một thành phần mới, vì ta sẽ muốn thêm nhiều dữ liệu hơn sau này và ta đang kết hợp đánh dấu với logic chuyển đổi.
Thành phần mới sẽ được gọi là AnimalDetails
. Để thực hiện, hãy tạo một folder mới:
- mkdir src/components/AnimalDetails
Tiếp theo, mở AnimalDetails.js
trong editor của bạn:
- nano src/components/AnimalDetails/AnimalDetails.js
Bên trong file , hãy 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 React from 'react'; 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
cài đặt hàm để thực hiện diet
là một mảng các chuỗi. Sau đó, bên trong thành phần, mã lặp qua 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 và đóng file .
Bạn cũng đang nhập một số CSS, vì vậy hãy thêm CSS đó ngay bây giờ.
Mở AnimalDetails.css
:
- nano src/components/AnimalDetails/AnimalDetails.css
Thêm một số CSS để cung cấp cho phần tử một đường viền và lề để tách các chi tiết khỏi phần còn lại của thành phần:
.details { border-top: gray solid 1px; margin: 20px 0; }
Ta sử dụng .details
để khớp luật với các phần tử có className
của details
.
Lưu và đóng file .
Đến đây bạn đã có một thành phần tùy chỉnh mới, bạn có thể thêm nó vào thành phần AnimalCard
của bạn . Mở AnimalCard.js
:
- nano src/components/AnimalCard/AnimalCard.js
Thay thế câu lệnh diet.join
bằng thành phần AnimalDetails
mới và chuyển diet
làm chỗ dựa bằng cách thêm các dòng được đánh dấu:
import React from 'react'; 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 và bạn sẽ thấy các chi tiết mới trong trình duyệt.
Chuyển thông tin chi tiết qua một thành phần với ...props
Các thành phần đ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 loại bỏ rõ ràng diet
khỏi đối số props
, nhưng bạn không sử dụng dữ liệu. Thay vào đó, bạn đang chuyển nó qua thành phần. Vốn dĩ không có gì sai về điều này - trên thực tế, tốt hơn là bạn nên 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 bạn khó bảo trì hơn. Khi nào bạn muốn chuyển dữ liệu mới đến AnimalDetails
, bạn cần cập nhật ba nơi: App
, nơi bạn chuyển các đạo cụ, AnimalDetails
, nơi sử dụng giá đỡ và AnimalCard
, là nơi đi giữa.
Một cách tốt hơn là thu thập bất kỳ đạo cụ không sử dụng nào bên trong AnimalCard
và sau đó chuyển trực tiếp chúng đến AnimalDetails
. Điều này cho bạn cơ hội áp dụng 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ề các đạo cụ hoặc các PropTypes
đang đi vào AnimalDetails
.
Để làm điều đó, bạn sẽ sử dụng toán tử phần còn lại đố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, name
biến sẽ là 'dog'
và biến props
sẽ là { diet: ['meat']}
.
Cho đến bây giờ, bạn đã vượt qua tất cả các đạo cụ như thể chúng là thuộc tính HTML, nhưng bạn cũng có thể sử dụng các đối tượng để gửi đạo cụ. Để sử dụng một đối tượng làm chỗ dựa, bạn cần sử dụng toán tử spread— ...props
bao quanh bởi dấu ngoặc nhọn. Điều này sẽ thay đổi mỗi cặp key-value thành một giá đỡ.
Mở AnimalCard.js
:
- nano src/components/AnimalCard/AnimalCard.js
Bên trong, 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 đạo cụ vào một biến gọi là props
. Sau đó, chuyển trực tiếp các đạo cụ đó tới AnimalDetails
:
import React from 'react'; 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 ý bạn có thể loại bỏ PropType
diet
vì bạn không sử dụng prop trong thành phần này.
Trong trường hợp này, bạn chỉ chuyển một chỗ AnimalDetails
cho AnimalDetails
. Trong trường hợp bạn có nhiều đạo cụ, thứ tự sẽ có vấn đề. Phần hỗ trợ sau sẽ overrides lên các phần thưởng trước đó, vì vậy nếu bạn có phần hỗ trợ mà bạn muốn ưu tiên, hãy đảm bảo phần hỗ trợ đó là 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ó thuộc tính cũng là giá trị được đặt tên.
Lưu và đóng file . Trình duyệt sẽ làm mới và mọi thứ sẽ giống nhau:
Để xem đối tượng ...props
thêm tính linh hoạt như thế nào, hãy chuyển tên scientificName
đến AnimalDetails
thông qua thành phần AnimalCard
.
Đầu tiên, hãy mở App.js
:
- nano src/components/App/App.js
Sau đó, vượt qua tên scientificName
làm chỗ dựa:
import React from 'react'; 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 và đóng file .
Bỏ qua AnimalCard
; bạn sẽ không cần thực hiện bất kỳ thay đổi nào ở đó. Sau đó, mở AnimalDetails
để bạn có thể sử dụng phần mềm hỗ trợ mới:
- nano src/components/AnimalDetails/AnimalDetails.js
Phần hỗ trợ mới sẽ là một chuỗi, bạn sẽ thêm chuỗi này vào danh sách details
cùng với một dòng khai báo PropType
:
import React from 'react'; ... 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 và đóng file . Khi bạn làm như vậy, trình duyệt sẽ làm mới và bạn sẽ thấy các chi tiết mới mà không có bất kỳ thay đổi nào đối với thành phần AnimalCard
:
Trong bước này, bạn đã học cách tạo các đạo cụ mẹ linh hoạt có thể lấy các đạo cụ không xác định và chuyể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 chung sẽ cung cấp cho bạn sự linh hoạt cần thiết để tạo ra các thành phần có trách nhiệm tập trung. Trong bước tiếp theo, bạn sẽ tạo thành phần mà có thể mất các thành phần chưa biết như một chỗ dựa bằng cách sử dụng được xây dựng trong children
chống đỡ.
Bước 3 - Tạo các thành phần Wrapper với children
Trong bước này, bạn sẽ tạo một thành phần shell bọc có thể lấy một group thành phần không xác định làm chỗ dựa. Điều này sẽ cung cấp cho bạn khả năng lồng ghép các thành phần như HTML tiêu chuẩn và nó sẽ cung cấp cho bạn một mẫu để tạo các shell bọc có thể tái sử dụng cho phép bạn tạo nhiều thành phần khác nhau cần thiết kế chung nhưng có nội thất linh hoạt.
Phản ứng cung cấp cho bạn một built-in prop gọi là children
thu thập bất kỳ thành phần trẻ em. Sử dụng điều này làm cho việc tạo các thành phần của shell bọc trở nên trực quan và dễ đọc.
Để bắt đầu, hãy tạo một thành phần mới có tên là Card
. Đây sẽ là một thành phần bao bọc để tạo ra một phong cách tiêu chuẩn cho bất kỳ thành phần thẻ mới nào.
Tạo một folder mới:
- mkdir src/components/Card
Sau đó, mở thành phần Card
trong editor của bạn:
- nano src/components/Card/Card.js
Tạo một thành phần lấy children
và title
làm đạo cụ và bao bọc chúng trong một div
bằng cách thêm mã sau:
import React from 'react'; 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, }
PropTypes
cho children
là mới. Phần mềm hỗ trợ 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 và đóng file .
Tiếp theo, thêm một số kiểu dáng. Mở Card.css
:
- nano src/components/Card/Card.css
Thẻ của bạn sẽ có một đường viền và một dòng dưới các chi tiết.
.card { border: black solid 1px; margin: 10px; padding: 10px; width: 200px; } .card-details { border-bottom: gray solid 1px; margin-bottom: 20px; }
Lưu và đóng file . Đến đây bạn đã có thành phần cần sử dụng. Bạn có thể bọc mỗi AnimalCard
với thành phần Card
trong App.js
, nhưng vì tên AnimalCard
ngụ ý rằng nó đã là một Card
, nên tốt hơn là sử dụng thành phần Card
bên trong AnimalCard
.
Mở AnimalCard
:
- nano src/components/AnimalCard/AnimalCard.js
Không giống như các đạo cụ khác, bạn không vượt qua children
một cách rõ ràng. 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 React from 'react'; 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, }
Không giống như một thành phần React, bạn không cần phải có một phần tử root duy nhất khi còn nhỏ. Đó là lý do tại sao PropType
for Card
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 chuyển các children
làm thành phần lồng nhau, bạn đang đặt cho thẻ một danh hiệu Animal
.
Lưu và đóng file . Khi bạn làm như vậy, trình duyệt sẽ làm mới và bạn sẽ thấy thành phần thẻ được cập nhật.
Đến đây bạn có một thành phần Card
có thể sử dụng lại có thể lấy bất kỳ số lượng con lồng nhau nào. Ưu điểm chính của việc này là bạn có thể sử dụng lại Card
với bất kỳ thành phần tùy ý nào. Nếu bạn muốn tạo thẻ Plant
, bạn có thể thực hiện bằng cách gói thông tin thực vật với thành phần Card
. Nó thậm chí không cần liên quan gì cả: Nếu bạn muốn sử dụng lại thành phần Card
trong một ứng dụng hoàn toàn khác có liệt kê những thứ như nhạc hoặc dữ liệu account , bạn cũng có thể làm điều đó. Thành phần Card
không quan tâm con cái là gì; 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 kiểu.
Nhược điểm của việc sử dụng children
là bạn chỉ có thể có một version của phần mềm hỗ trợ trẻ em. Đôi khi, bạn cần một thành phần có JSX tùy chỉnh ở nhiều nơi. May mắn là bạn có thể thực hiện bằng cách chuyển các thành phần JSX và React làm đạo cụ, mà ta sẽ đề cập trong bước tiếp theo.
Bước 4 - Chuyển các thành phần làm đạo cụ
Trong bước này, bạn sẽ sửa đổi thành phần Card
của bạn để lấy các thành phần khác làm đạo cụ. Điều này sẽ cung cấp cho thành phần của bạn sự linh hoạt tối đa để hiển thị các thành phần 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 thành phần làm đạo cụ, giúp thành phần shell bọc của bạn có khả năng thích ứng với nhiều nhu cầu khác nhau trong khi vẫn giữ được giao diện và cấu trúc chuẩn.
Đến cuối bước này, bạn sẽ có một thành phần có thể bọc các thành phần con và cũng hiển thị các thành phần 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 thành phần 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 thành phần Card
để lấy một phần tử React tùy ý được gọi là details
.
Đầu tiên, hãy mở thành phần Card
:
- nano src/components/Card/Card.js
Tiếp theo, thêm một phần mềm hỗ trợ mới có tên là details
và đặt nó bên dưới phần tử <h2>
:
import React from 'react'; 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, }
Giá đỡ này sẽ có cùng loại với children
, nhưng 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 user không chuyển thông tin chi tiết, thành phần sẽ vẫn có hiệu lực và sẽ không hiển thị thêm bất kỳ thứ gì.
Lưu và đóng file . Trang sẽ được làm mới và bạn sẽ thấy hình ảnh giống như trước đây:
Bây giờ thêm một số chi tiết vào thẻ AnimalCard
. Đầu tiên, hãy mở AnimalCard
.
- nano src/components/AnimalCard/AnimalCard.js
Vì thành phần Card
đã sử dụng phần tử children
, bạn cần chuyển thành phần JSX mới làm chỗ dựa. Vì tất cả đều là động vật có vú, hãy thêm hình ảnh đó vào thẻ, nhưng bọc nó trong <em>
để in nghiêng.
import React from 'react'; ... 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 các file . Khi bạn làm như vậy, trình duyệt sẽ làm mới và bạn sẽ thấy bản cập nhật, bao gồm cả cụm từ Động vật có vú .
Phần mềm hỗ trợ này đã rất mạnh 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 đánh dấu phức tạp, bạn sẽ không muốn chuyển nó trực tiếp trong phần hỗ trợ; điều này sẽ khó đọc. Thay vào đó, bạn có thể tạo một thành phần riêng biệt và sau đó chuyển thành phần đó làm chỗ dựa.
Để xem điều này tại nơi làm việc, hãy chuyển AnimalDetails
đến phần hỗ trợ details
:
import React from 'react'; ... export default function AnimalCard({ name, size, ...props }) { return( <Card title="Animal" details={ <AnimalDetails {...props} /> } > <h3>{name}</h3> <div>{size}kg</div> </Card> ) } ...
AnimalDetails
phức tạp hơn và có một số dòng đánh dấu. Nếu bạn thêm nó trực tiếp vào details
, nó sẽ làm tăng đáng kể chỗ dựa và gây khó đọc.
Lưu và đóng file . Khi bạn làm như vậy, trình duyệt sẽ làm mới và thông tin chi tiết sẽ xuất hiện ở đầu thẻ.
Đến đây bạn có một thành phần 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 chỗ dựa duy nhất; bạn có thể chuyển các phần tử cho bao nhiêu đạo cụ tùy thích. Điều này cung cấp cho bạn khả năng tạo các thành phần bao bọc 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 thành phần trong khi vẫn giữ được phong cách và chức năng tổng thể của nó.
Chuyển một thành phần làm chỗ dựa không phải là hoàn hảo. Nó khó đọc hơn một chút và không rõ ràng bằng những children
lướt qua, nhưng chúng rất linh hoạt và bạn có thể sử dụng bao nhiêu trong số chúng tùy thích trong một thành phần. Bạn nên sử dụng children
trước, nhưng đừng ngần ngại rơi lại đạo cụ nếu điều đó là không đủ.
Trong bước này, bạn đã học cách chuyển các thành phần JSX và React làm đạo cụ cho một thành phần khác. Điều này sẽ cung cấp cho thành phần của bạn sự linh hoạt để xử lý nhiều tình huống trong đó một thành phần shell bọc có thể cần nhiều đạo cụ để xử lý JSX hoặc các thành phần.
Kết luận
Bạn đã tạo ra nhiều thành phần gói có thể hiển thị dữ liệu một cách linh hoạt trong khi vẫn giữ được cấu trúc và giao diện có thể đoán trước được. Bạn đã tạo các thành phần có thể thu thập và chuyển các đạo cụ không xác định cho các thành phần lồng nhau. Bạn cũng đã sử dụng phần mềm hỗ trợ children
được tích hợp sẵn để tạo các thành phần shell bọc 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 thành phần có thể lấy các thành phần JSX hoặc React làm chỗ dựa để thành phần shell bọc của bạn có thể xử lý nhiều version của các tùy chỉnh khác nhau.
Các thành phần của gói 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 user 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. Bạn sẽ thấy mình quay lại nó nhiều lần.
Nếu bạn muốn xem thêm các hướng dẫn về React, hãy xem trang Chủ đề React của ta hoặc quay lại trang Cách viết mã trong chuỗi React.js .
Các tin liên quan