ReactJS: Cách chia sẻ state giữa các component với ngữ cảnh (context)

Giới thiệu

Trong bài hướng dẫn này, bạn sẽ học cách chia sẻ state trên nhiều component bằng cách sử dụng ngữ cảnh React. React context là một giao diện để chia sẻ thông tin với các component khác mà không cần truyền dữ liệu làm prop một cách tường minh. Điều này có nghĩa là bạn có thể chia sẻ thông tin giữa component cha và component con lồng nhau sâu hoặc lưu trữ dữ liệu trên toàn trang web ở một nơi duy nhất và truy cập chúng ở bất kỳ đâu trong ứng dụng. Bạn thậm chí có thể cập nhật dữ liệu từ các compnent lồng nhau bằng cách cung cấp các chức năng cập nhật cùng với dữ liệu.

Ngữ cảnh (context) React đủ linh hoạt để sử dụng như một hệ thống quản lý state tập trung cho dự án của bạn hoặc bạn có thể mở rộng phạm vi nó đến các phần nhỏ hơn trong ứng dụng của mình. Với ngữ cảnh, bạn có thể chia sẻ dữ liệu trên toàn ứng dụng mà không cần bất kỳ công cụ bổ sung nào của bên thứ ba và với một lượng nhỏ cấu hình. Điều này cung cấp một giải pháp thay thế trọng lượng nhẹ hơn cho các công cụ như Redux, có thể trợ giúp với các ứng dụng lớn hơn nhưng có thể yêu cầu quá nhiều thiết lập cho các dự án quy mô vừa.

Trong suốt hướng dẫn này, bạn sẽ sử dụng ngữ cảnh để xây dựng một ứng dụng sử dụng các tập dữ liệu chung trên các component khác nhau. Để minh họa điều này, bạn sẽ tạo một trang web nơi người dùng có thể tạo các món salad tùy chỉnh. Trang web sẽ sử dụng ngữ cảnh để lưu trữ thông tin khách hàng, các món yêu thích và món salad tùy chỉnh. Sau đó, bạn sẽ truy cập dữ liệu đó và cập nhật nó trong toàn bộ ứng dụng mà không cần truyền dữ liệu qua prop. Đến cuối hướng dẫn này, bạn sẽ học cách sử dụng ngữ cảnh để lưu trữ dữ liệu ở các cấp độ khác nhau của dự án và cách truy cập và cập nhật dữ liệu trong các component lồng nhau.

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 Create React App. Sau đó, bạn sẽ xóa dự án mẫu và các tệp 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 tệp đơn giản để tổ chức các component của mình. Điều này sẽ cung cấp cho bạn một cơ sở vững chắc để xây dựng ứng dụng mẫu của hướng dẫn này để tạo style trong bước tiếp theo.

Để bắt đầu, hãy thực hiện một dự án mới. Bạn mở terminal và 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 context-tutorial

Sau khi dự án kết thúc, hãy thay đổi vào thư mục:

cd

context-tutorial

Khởi động dự án với lệnh:

npm

start

http://

your_domain

:3000

Bạn sẽ nhận được một máy chủ cục bộ đang chạy. Nếu dự án không mở trong cửa sổ trình duyệt, bạn có thể mở nó bằng http://localhost:3000/ . Nếu bạn đang chạy điều này từ một máy chủ từ xa, địa chỉ sẽ là .

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:

Dự án mẫu React

Bạn sẽ xây dựng một tập hợp các component tùy chỉnh hoàn toàn mới, vì vậy bạn sẽ 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ở component src/App.js. Đây là component gốc được đưa vào trang. Tất cả các component sẽ bắt đầu từ đây. Bạn sửa lại file để trong đó chỉ còn chứa như sau:

import

'./App.css'

;

function

App

(

)

{

return

<

>

<

/

>

;

}

export

default

App

;

Mở một terminal khác và thực hiện thao tác xóa file logo.svg:

rm

src/logo.svg

Tạo thư mục components:

mkdir

src/components

Tạo thư mục App:

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à chỉnh sửa:

import

React

from

'react'

;

import

ReactDOM

from

'react-dom'

;

import

'./index.css'

;

import

App

from

'.

/components/App

/App'

;

import

*

as

serviceWorker

from

'./reportWebVitals'

;

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 file lại và quay lại trang web ta được một trang web trống.

màn hình trống trong chrome

Bây giờ 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 tệp đơn giản. Điều này sẽ giúp bạn giữ cho các component của bạn cô lập và độc lập.

Tạo một thư mục được gọi components trong thư mục src, components sẽ là nơi chứa tất cả các component tùy chỉnh của bạn. 

Bước 2 – Xây dựng cơ sở cho ứng dụng của bạn

Trong bước này, bạn sẽ xây dựng cấu trúc chung của trình tạo salad tùy chỉnh của mình. Bạn sẽ tạo các component để hiển thị các lớp phủ có thể có, danh sách các lớp phủ đã chọn và thông tin khách hàng. Khi bạn xây dựng ứng dụng với dữ liệu tĩnh, bạn sẽ thấy cách các phần thông tin khác nhau được sử dụng trong nhiều component khác nhau và cách xác định các phần dữ liệu sẽ hữu ích trong một ngữ cảnh.

Đây là một ví dụ về ứng dụng bạn sẽ xây dựng:

Trang web xây dựng salad

Lưu ý cách có thông tin mà bạn có thể cần sử dụng trên các component. Ví dụ: tên người dùng (đối với mẫu này là Kwame) hiển thị dữ liệu người dùng trong khu vực điều hướng, nhưng bạn cũng có thể cần thông tin người dùng để xác định các mục yêu thích hoặc cho trang thanh toán. Thông tin người dùng sẽ cần phải được truy cập bởi bất kỳ component nào trong ứng dụng. Nhìn vào chính trình tạo salad, mỗi thành phần salad sẽ cần có thể cập nhật danh sách Your Salad ở cuối màn hình, vì vậy bạn sẽ cần lưu trữ và cập nhật dữ liệu đó từ một vị trí có thể truy cập được cho từng component.

Bắt đầu bằng cách mã hóa cứng tất cả dữ liệu để bạn có thể tìm ra cấu trúc ứng dụng của mình. Sau đó, bạn sẽ thêm ngữ cảnh bắt đầu trong bước tiếp theo. Ngữ cảnh cung cấp nhiều giá trị nhất khi các ứng dụng bắt đầu phát triển, vì vậy trong bước này, bạn sẽ xây dựng một số component để hiển thị cách ngữ cảnh hoạt động trên một cây component. Đối với các component hoặc thư viện nhỏ hơn, bạn thường có thể sử dụng các component wrapper và kỹ thuật quản lý state cấp thấp hơn, như React Hooks và quản lý dựa trên lớp.

Vì bạn đang xây dựng một ứng dụng nhỏ với nhiều component, hãy cài đặt JSS để đảm bảo rằng sẽ không có bất kỳ xung đột tên lớp nào và để bạn có thể thêm các kiểu trong cùng một tệp như một component. Để biết thêm về JSS, hãy xem Cách tạo style cho các component.

Chạy lệnh sau:

npm

install

react-jss

Bây giờ bạn đã cài đặt JSS, hãy xem xét các component khác nhau mà bạn sẽ cần. Ở đầu trang, bạn sẽ có một component Navigation để lưu trữ thông điệp chào mừng. Componet tiếp theo sẽ là SaladMaker, nó có nhiệm vụ giữ tiêu đề cùng với trình tạo và danh sách Your Salad ở dưới cùng. Phần có các thành phần sẽ là một component riêng biệt được gọi là SaladBuilder, được lồng vào bên trong SaladMaker. Mỗi thành phần sẽ là một thể hiện của một component SaladItem. Cuối cùng, danh sách dưới cùng sẽ là một component được gọi SaladSummary.

Lưu ý: Các component không cần phải được chia theo cách này. Khi bạn làm việc trên các ứng dụng của mình, cấu trúc của bạn sẽ thay đổi và phát triển khi bạn thêm nhiều chức năng hơn. Ví dụ này nhằm cung cấp cho bạn một cấu trúc để khám phá cách ngữ cảnh ảnh hưởng đến các component khác nhau trong cây.

Bây giờ bạn đã có ý tưởng về các component bạn sẽ cần, hãy tạo một thư mục cho từng component:

mkdir

src/components/Navigation

mkdir

src/components/SaladMaker

mkdir

src/components/SaladItem

mkdir

src/components/SaladBuilder

mkdir

src/components/SaladSummary

Tiếp theo ta xây dựng các component từ trên xuống bắt đầu từ Navigation. Đầu tiên, mở file component trong trình soạn thảo văn bản:

Tạo một component có tên Navigation.js và thêm một số style để tạo đường viền và đệm cho Navigation:

import

{

createUseStyles

}

from

'react-jss'

;

const

useStyles

=

createUseStyles

(

{

wrapper

:

{

borderBottom

:

'black solid 1px'

,

padding

:

[

15

,

10

]

,

textAlign

:

'right'

,

}

}

)

;

export

default

function

Navigation

(

)

{

const

classes

=

useStyles

(

)

;

return

(

<

div className

=

{

classes

.

wrapper

}

>

Welcome

,

Kwame

<

/

div

>

)

}

Trong đoạn code trên, vì bạn đang sử dụng JSS, bạn có thể tạo các đối tượng style trực tiếp trong component thay vì dùng file CSS. Thẻ div sẽ có một phần đệm, một đường viền solid black và căn chỉnh văn bản ở bên phải với textAlign.

Lưu file lại. Tiếp theo, hãy mở App.js, đây là component gốc của dự án, sau đó import component Navigation và hiển thị nó bên trong các thẻ trống bằng cách thêm các dòng được đánh dấu như sau:

import

Navigation

from

'../Navigation/Navigation'

;

function

App

(

)

{

return

(

<

>

<

Navigation

/

>

<

/

>

)

;

}

export

default

App

;

Lưu file lại và quay lại trang web, bạn refresh sẽ được kết quả dạng như sau:

Thanh điều hướng

Hãy coi thanh điều hướng như một component chung, vì trong ví dụ này, nó đóng vai trò như một component mẫu sẽ được sử dụng lại trên mọi trang.

Component tiếp theo sẽ là SaladMaker. Nó sẽ chỉ hiển thị trên một số trang nhất định hoặc ở một số trạng thái nhất định.

Mở file SaladMaker.js ra và đưa vào đoạn code sau:

import

{

createUseStyles

}

from

'react-jss'

;

const

useStyles

=

createUseStyles

(

{

wrapper

:

{

textAlign

:

'center'

,

}

}

)

;

export

default

function

SaladMaker

(

)

{

const

classes

=

useStyles

(

)

;

return

(

<

>

<

h1 className

=

{

classes

.

wrapper

}

>

<

span role

=

"img"

aria

-

label

=

"salad"

>

🥗

<

/

span

>

Build Your Custom Salad

!

<

span role

=

"img"

aria

-

label

=

"salad"

>

🥗

<

/

span

>

<

/

h1

>

<

/

>

)

}

Trong đoạn code trên, bạn đang sử dụng textAlign để căn giữa component trên trang. Các thuộc tính role và aria-label của phần tử span sẽ giúp hỗ trợ khả năng truy cập bằng Ứng dụng Internet đa dạng có thể truy cập (ARIA).

Lưu file lại, sau đó mở App.js ra để import component SaladMaker và hiển thị sau component Navigation:

import

Navigation

from

'../Navigation/Navigation'

;

import

SaladMaker

from

'../SaladMaker/SaladMaker'

;

function

App

(

)

{

return

(

<

>

<

Navigation

/

>

<

SaladMaker

/

>

<

/

>

)

;

}

export

default

App

;

Lưu file lại và quay lại trang web ta được kết quả dạng như sau:

Trang làm salad

Tiếp theo, ta tạo component SaladItem. Đây sẽ là một thẻ (card) cho từng thành phần riêng lẻ.

Mở file SaladItem.js ra. Component này sẽ có ba phần: tên của món, một biểu tượng hiển thị món đó có phải là món yêu thích của người dùng hay không và một biểu tượng cảm xúc được đặt bên trong một nút sẽ thêm món đó vào món salad khi nhấp chuột. Thêm các dòng sau vào SaladItem.js:

import

PropTypes

from

'prop-types'

;

import

{

createUseStyles

}

from

'react-jss'

;

const

useStyles

=

createUseStyles

(

{

add

:

{

background

:

'none'

,

border

:

'none'

,

cursor

:

'pointer'

,

}

,

favorite

:

{

fontSize

:

20

,

position

:

'absolute'

,

top

:

10

,

right

:

10

,

}

,

image

:

{

fontSize

:

80

}

,

wrapper

:

{

border

:

'lightgrey solid 1px'

,

margin

:

20

,

padding

:

25

,

position

:

'relative'

,

textAlign

:

'center'

,

textTransform

:

'capitalize'

,

width

:

200

,

}

}

)

;

export

default

function

SaladItem

(

{

image

,

name

}

)

{

const

classes

=

useStyles

(

)

;

const

favorite

=

true

;

return

(

<

div className

=

{

classes

.

wrapper

}

>

<

h3

>

{

name

}

<

/

h3

>

<

span className

=

{

classes

.

favorite

}

aria

-

label

=

{

favorite

?

'Favorite'

:

'Not Favorite'

}

>

{

favorite

?

'😋'

:

''

}

<

/

span

>

<

button className

=

{

classes

.

add

}

>

<

span className

=

{

classes

.

image

}

role

=

"img"

aria

-

label

=

{

name

}

>

{

image

}

<

/

span

>

<

/

button

>

<

/

div

>

)

}

SaladItem

.

propTypes

=

{

image

:

PropTypes

.

string

.

isRequired

,

name

:

PropTypes

.

string

.

isRequired

,

}

Trong đoạn code trên, image và name sẽ là các prop. Trong đoạn code cũng có sử ​​dụng biến favorite và toán tử ba ngôi để xác định xem biểu tượng favorite có xuất hiện hay không. Biến favorite sau này sẽ được xác định với bối cảnh là một phần của hồ sơ. Bây giờ, hãy đặt nó thành true. Tạo style để đặt biểu tượng yêu thích ở góc trên bên phải của thẻ và xóa đường viền và nền mặc định trên nút. Class wrapper sẽ bổ sung thêm một đường viền nhỏ và biến đổi một số văn bản. Cuối cùng, PropTypes thêm một hệ thống kiểu yếu để cung cấp một số thực thi để đảm bảo kiểu prop sai không được truyền đi.

Lưu file lại. Bây giờ, bạn sẽ cần kết xuất các mục khác nhau. Bạn sẽ làm điều đó với một component tên SaladBuilder, sẽ chứa danh sách các mục mà nó sẽ chuyển đổi thành một loạt các component SaladItem:

Mở SaladBuilder.js ra, nếu đây là một ứng dụng production, thì dữ liệu này thường đến từ Giao diện lập trình ứng dụng (API). Nhưng hiện tại, hãy sử dụng danh sách các component được mã hóa cứng:

import

SaladItem

from

'../SaladItem/SaladItem'

;

import

{

createUseStyles

}

from

'react-jss'

;

const

useStyles

=

createUseStyles

(

{

wrapper

:

{

display

:

'flex'

,

flexWrap

:

'wrap'

,

padding

:

[

10

,

50

]

,

justifyContent

:

'center'

,

}

}

)

;

const

ingredients

=

[

{

image

:

'🍎'

,

name

:

'apple'

,

}

,

{

image

:

'🥑'

,

name

:

'avocado'

,

}

,

{

image

:

'🥦'

,

name

:

'broccoli'

,

}

,

{

image

:

'🥕'

,

name

:

'carrot'

,

}

,

{

image

:

'🍷'

,

name

:

'red wine dressing'

,

}

,

{

image

:

'🍚'

,

name

:

'seasoned rice'

,

}

,

]

;

export

default

function

SaladBuilder

(

)

{

const

classes

=

useStyles

(

)

;

return

(

<

div className

=

{

classes

.

wrapper

}

>

{

ingredients

.

map

(

ingredient

=>

(

<

SaladItem key

=

{

ingredient

.

name

}

image

=

{

ingredient

.

image

}

name

=

{

ingredient

.

name

}

/

>

)

)

}

<

/

div

>

)

}

Đoạn mã trên sử dụng phương thức mảng map() để ánh xạ từng mục trong danh sách, truyền name và image dưới dạng các prop cho một component SaladItem. Hãy chắc chắn thêm key vào từng mục khi bạn lập bản đồ. Style cho component này với việc thêm cách thức hiển thị là flex sử dụng bố cục flexbox, bao ngoài các component và căn giữa chúng.

Lưu file lại.

Cuối cùng, kết xuất component SaladMaker để nó sẽ xuất hiện trong trang.

Mở SaladMaker ra sau đó import SaladBuilder và hiển thị sau tiêu đề <h1>:

import

{

createUseStyles

}

from

'react-jss'

;

import

SaladBuilder

from

'../SaladBuilder/SaladBuilder'

;

const

useStyles

=

createUseStyles

(

{

wrapper

:

{

textAlign

:

'center'

,

}

}

)

;

export

default

function

SaladMaker

(

)

{

const

classes

=

useStyles

(

)

;

return

(

<

>

<

h1 className

=

{

classes

.

wrapper

}

>

<

span role

=

"img"

aria

-

label

=

"salad"

>

🥗

<

/

span

>

Build Your Custom Salad

!

<

span role

=

"img"

aria

-

label

=

"salad"

>

🥗

<

/

span

>

<

/

h1

>

<

SaladBuilder

/

>

<

/

>

)

}

Lưu file lại và quay lại trang web ta được kết quả như sau:

Thợ làm salad với các mặt hàng

Bước cuối cùng là thêm phần tóm tắt của món salad đang thực hiện. Component này sẽ hiển thị danh sách các mục mà người dùng đã chọn. Hiện tại, bạn sẽ mã hóa các mặt hàng một cách khó khăn. Bạn sẽ cập nhật chúng với ngữ cảnh trong Bước 3.

Mở SaladSummary.js ra. Component sẽ là một tiêu đề và một danh sách các mục chưa được sắp xếp. Bạn sẽ sử dụng flexbox để bao chúng:

import

{

createUseStyles

}

from

'react-jss'

;

const

useStyles

=

createUseStyles

(

{

list

:

{

display

:

'flex'

,

flexDirection

:

'column'

,

flexWrap

:

'wrap'

,

maxHeight

:

50

,

'& li'

:

{

width

:

100

}

}

,

wrapper

:

{

borderTop

:

'black solid 1px'

,

display

:

'flex'

,

padding

:

25

,

}

}

)

;

export

default

function

SaladSummary

(

)

{

const

classes

=

useStyles

(

)

;

return

(

<

div className

=

{

classes

.

wrapper

}

>

<

h2

>

Your Salad

<

/

h2

>

<

ul className

=

{

classes

.

list

}

>

<

li

>

Apple

<

/

li

>

<

li

>

Avocado

<

/

li

>

<

li

>

Carrots

<

/

li

>

<

/

ul

>

<

/

div

>

)

}

Lưu file lại sau mở SaladMaker.js để hiển thị mục. Import và thêm SaladSummary vào sau SaladBuilder:

import

{

createUseStyles

}

from

'react-jss'

;

import

SaladBuilder

from

'../SaladBuilder/SaladBuilder'

;

import

SaladSummary

from

'../SaladSummary/SaladSummary'

;

const

useStyles

=

createUseStyles

(

{

wrapper

:

{

textAlign

:

'center'

,

}

}

)

;

export

default

function

SaladMaker

(

)

{

const

classes

=

useStyles

(

)

;

return

(

<

>

<

h1 className

=

{

classes

.

wrapper

}

>

<

span role

=

"img"

aria

-

label

=

"salad"

>

🥗

<

/

span

>

Build Your Custom Salad

!

<

span role

=

"img"

aria

-

label

=

"salad"

>

🥗

<

/

span

>

<

/

h1

>

<

SaladBuilder

/

>

<

SaladSummary

/

>

<

/

>

)

}

Lưu file lại và quay lại trang web và đóng tập tin. Khi bạn làm như vậy, trang sẽ làm mới và bạn sẽ tìm thấy ứng dụng đầy đủ:

Trang web xây dựng salad

Như vậy, ở đây có dữ liệu được chia sẻ trong toàn bộ ứng dụng. Component Navigation và SaladItem đều cần biết điều gì đó về người dùng: tên của họ và danh sách yêu thích của họ. SaladItem cũng cần phải cập nhật dữ liệu có thể truy cập vào các component SaladSummary. Các component có chung một gốc (cha), nhưng việc truyền dữ liệu xuống thông qua cây sẽ khó khăn và dễ xảy ra lỗi.

Đó là lúc ta cần đến ngữ cảnh. Bạn có thể khai báo dữ liệu trong một nơi chung và sau đó truy cập mà không cần truyền nó xuống hệ thống phân cấp của các component một cách rõ ràng.

Trong bước này, bạn đã tạo một ứng dụng để cho phép người dùng tạo món salad từ danh sách các tùy chọn. Bạn đã tạo một tập hợp các component cần truy cập hoặc cập nhật dữ liệu được kiểm soát bởi các component khác. Trong bước tiếp theo, bạn sẽ sử dụng ngữ cảnh để lưu trữ dữ liệu và truy cập nó trong các component con.

Bước 3 – Cung cấp dữ liệu từ component gốc

Trong bước này, bạn sẽ sử dụng ngữ cảnh để lưu trữ thông tin khách hàng ở gốc của component. Bạn sẽ tạo một ngữ cảnh tùy chỉnh, sau đó sử dụng một component wrapper đặc biệt được gọi là a Provider sẽ lưu trữ thông tin ở gốc của dự án. Sau đó, bạn sẽ sử dụng Hoock useContext để kết nối với trình cung cấp trong các component lồng nhau để bạn có thể hiển thị thông tin tĩnh. Đến cuối bước này, bạn sẽ có thể cung cấp kho thông tin tập trung và sử dụng thông tin được lưu trữ trong ngữ cảnh ở nhiều component khác nhau.

Bối cảnh cơ bản nhất của nó là một giao diện để chia sẻ thông tin. Nhiều ứng dụng có một số thông tin chung mà chúng cần chia sẻ trên toàn ứng dụng, chẳng hạn như tùy chọn của người dùng, thông tin chủ đề và các thay đổi ứng dụng trên toàn bộ trang web. Với ngữ cảnh, bạn có thể lưu trữ thông tin đó ở cấp cơ sở sau đó truy cập nó ở bất kỳ đâu. Vì bạn đặt thông tin ở gốc, nên bạn biết thông tin đó sẽ luôn có sẵn và sẽ luôn được cập nhật.

Để thêm ngữ cảnh, hãy tạo một component mới có tên UserUser sẽ không phải là một component thông thường, trong đó bạn sẽ sử dụng nó như một component và như một phần dữ liệu cho một Hook đặc biệt được gọi useContext. Hiện tại, hãy giữ cấu trúc tệp phẳng, nhưng nếu bạn sử dụng nhiều ngữ cảnh, có thể đáng để chuyển chúng sang một cấu trúc thư mục khác.

Tiếp theo, mở User.js ra, import createContext, sau đó thực thi hàm và xuất kết quả:

import

{

createContext

}

from

'react'

;

const

UserContext

=

createContext

(

)

;

export

default

UserContext

;

Bằng cách thực thi hàm createContext(), bạn đã đăng ký ngữ cảnh. Kết quả là bạn có UserContext và bạn sẽ sử dụng trong các component của mình.

Lưu file lại.

Bước tiếp theo là áp dụng ngữ cảnh cho một tập hợp các phần tử. Để làm điều đó, bạn sẽ sử dụng một component được gọi là a ProviderProvider sẽ thiết lập dữ liệu và sau đó bao bọc (wrapper) một số component con. Bất kỳ component con nào được bao bọc sẽ có quyền truy cập vào dữ liệu từ Provider với useContextHook.

Vì dữ liệu người dùng sẽ không đổi trong toàn bộ dự án, hãy đặt nó lên cây compnent càng cao càng tốt. Trong ứng dụng này, bạn sẽ đặt nó ở cấp gốc trong component App:

Mở App ra, thêm các dòng mã được đánh dấu sau để import ngữ cảnh và chuyển dữ liệu:

import

Navigation

from

'../Navigation/Navigation'

;

import

SaladMaker

from

'../SaladMaker/SaladMaker'

;

import

UserContext

from

'../User/User'

;

const

user

=

{

name

:

'Kwame'

,

favorites

:

[

'avocado'

,

'carrot'

]

}

function

App

(

)

{

return

(

<

UserContext

.

Provider value

=

{

user

}

>

<

Navigation

/

>

<

SaladMaker

/

>

<

/

UserContext

.

Provider

>

)

;

}

export

default

App

;

Trong một ứng dụng điển hình, bạn sẽ tìm nạp dữ liệu người dùng hoặc lưu trữ dữ liệu đó trong quá trình hiển thị phía máy chủ. Trong trường hợp này, bạn đã mã hóa cứng một số dữ liệu mà bạn có thể nhận được từ API. Bạn đã tạo một đối tượng có tên user chứa tên người dùng dưới dạng một chuỗi và một mảng các thành phần yêu thích.

Tiếp theo, bạn import UserContext, sau đó bọc Navigation và SaladMaker bởi một component được gọi là UserContext.Provider. Chú ý là trong trường hợp này UserContext hoạt động như một component React tiêu chuẩn. Component này sẽ nhận một prop duy nhất được gọi là value. Prop đó sẽ là dữ liệu bạn muốn chia sẻ, trong trường hợp này là đối tượng user.

Lưu file lại. Bây giờ dữ liệu đã có sẵn trong toàn bộ ứng dụng. Tuy nhiên, để sử dụng dữ liệu, bạn sẽ cần import và truy cập ngữ cảnh một lần nữa.

Bây giờ bạn đã thiết lập ngữ cảnh, bạn có thể bắt đầu thay thế dữ liệu được mã hóa cứng trong component của bạn bằng các giá trị động. Bắt đầu bằng cách thay thế tên được mã hóa cứng trong Navigation bằng dữ liệu người dùng mà bạn đã thiết lập với UserContext.Provider.

Mở file Navigation.js ra, bên trong Navigation, import Hook useContext từ React và UserContext từ thư mục component. Sau đó, gọi useContext bằng cách sử dụng UserContext như một đối số. Không giống như UserContext.Provider, bạn không cần phải kết xuất UserContext trong JSX. Hook sẽ trả về dữ liệu mà bạn đã cung cấp trong phần prop value. Lưu dữ liệu vào một biến mới được gọi, user, đây là một đối tượng chứa name và favorites. Sau đó, bạn có thể thay thế tên được mã hóa cứng bằng user.name:

import

{

useContext

}

from

'react'

;

import

{

createUseStyles

}

from

'react-jss'

;

import

UserContext

from

'../User/User'

;

const

useStyles

=

createUseStyles

(

{

wrapper

:

{

outline

:

'black solid 1px'

,

padding

:

[

15

,

10

]

,

textAlign

:

'right'

,

}

}

)

;

export

default

function

Navigation

(

)

{

const

user

=

useContext

(

UserContext

)

;

const

classes

=

useStyles

(

)

;

return

(

<

div className

=

{

classes

.

wrapper

}

>

Welcome

,

{

user

.

name

}

<

/

div

>

)

}

UserContext hoạt động như một component trong App.js, nhưng ở đây bạn đang sử dụng nó như một phần dữ liệu. Tuy nhiên, nó vẫn có thể hoạt động như một component nếu bạn muốn. Bạn có thể truy cập cùng một dữ liệu bằng cách sử dụng Consumer là một phần của UserContext. Bạn truy xuất dữ liệu bằng cách thêm UserContext.Consumer vào JSX của mình, sau đó sử dụng một hàm như là con để truy cập dữ liệu.

Mặc dù có thể sử dụng component Consumer, nhưng sử dụng Hook thường có thể ngắn hơn và dễ đọc hơn, trong khi vẫn cung cấp cùng một thông tin cập nhật. Đây là lý do tại sao hướng dẫn này sử dụng cách tiếp cận Hook.

Lưu file lại và quay lại trang web, bạn refresh và bạn sẽ thấy kết quả tương tự, nhưng lần này dữ liệu đã là động:

Trong trường hợp này, dữ liệu không di chuyển qua nhiều component. Cây component đại diện cho đường dẫn mà dữ liệu được truyền đi sẽ trông giống như sau:

| UserContext.Provider
  | Navigation

Bạn có thể truyền tên người dùng như là prop và ở quy mô này, đó có thể là một chiến lược hiệu quả. Nhưng khi ứng dụng phát triển lên, có khả năng component Navigation sẽ cần phải di chuyển trong cây component. Có thể có một component được gọi là Header hao bọc component Navigation và một component khác chẳng hạn như a TitleBar, hoặc có thể bạn sẽ tạo một component Template và sau đó lồng Navigation vào đó. Bằng cách sử dụng ngữ cảnh, bạn sẽ không phải cấu trúc lại Navigation miễn Provider nằm phía trên trong cây component, giúp cho việc tái cấu trúc trở nên dễ dàng hơn.

Component tiếp theo cần dữ liệu người dùng là SaladItem. Trong SaladItem, bạn sẽ cần mảng favourites của người dùng. Bạn sẽ hiển thị biểu tượng cảm xúc có điều kiện nếu thành phần được người dùng yêu thích.

Mở file SaladItem.js ra, import useContext và UserContext sau đó gọi useContext với UserContext. Sau đó, hãy kiểm tra xem thành phần có trong mảng favorites hay không bằng cách sử dụng phương thức includes:

import

{

useContext

}

from

'react'

;

import

PropTypes

from

'prop-types'

;

import

{

createUseStyles

}

from

'react-jss'

;

import

UserContext

from

'../User/User'

;

const

useStyles

=

createUseStyles

(

{

...

}

)

;

export

default

function

SaladItem

(

{

image

,

name

}

)

{

const

classes

=

useStyles

(

)

;

const

user

=

useContext

(

UserContext

)

;

const

favorite

=

user

.

favorites

.

includes

(

name

)

;

return

(

<

div className

=

{

classes

.

wrapper

}

>

<

h3

>

{

name

}

<

/

h3

>

<

span className

=

{

classes

.

favorite

}

aria

-

label

=

{

favorite

?

'Favorite'

:

'Not Favorite'

}

>

{

favorite

?

'😋'

:

''

}

<

/

span

>

<

button className

=

{

classes

.

add

}

>

<

span className

=

{

classes

.

image

}

role

=

"img"

aria

-

label

=

{

name

}

>

{

image

}

<

/

span

>

<

/

button

>

<

/

div

>

)

}

SaladItem

.

propTypes

=

{

image

:

PropTypes

.

string

.

isRequired

,

name

:

PropTypes

.

string

.

isRequired

,

}

Lưu  file lại và quay lại trang web bạn sẽ thấy rằng chỉ những mục yêu thích mới có biểu tượng cảm xúc:

Món salad ưa thích với bơ và cà rốt

Không giống như Navigation, ngữ cảnh đang đi xa hơn nhiều. Cây component sẽ trông giống như sau:

| User.Provider
  | SaladMaker
    | SaladBuilder
      | SaladItem

Thông tin bỏ qua hai component trung gian mà không có bất kỳ prop nào. Nếu bạn phải truyền dữ liệu dưới dạng prop qua toàn bộ cây, thì sẽ rất nhiều công việc và bạn có nguy cơ gặp phải một nhà phát triển trong tương lai cấu trúc lại mã và quên truyền prop xuống. Với ngữ cảnh, bạn có thể tin tưởng mã sẽ hoạt động khi ứng dụng phát triển và phát triển.

Trong bước này, bạn đã tạo một ngữ cảnh và sử dụng a Provider để đặt dữ liệu trong cây component. Bạn cũng đã truy cập ngữ cảnh với Hook useContext và ngữ cảnh được sử dụng trên nhiều component. Dữ liệu này là tĩnh và do đó không bao giờ thay đổi sau khi thiết lập ban đầu, nhưng sẽ có lúc bạn cần chia sẻ dữ liệu và cũng có thể sửa đổi dữ liệu trên nhiều component. Trong bước tiếp theo, bạn sẽ cập nhật dữ liệu lồng nhau bằng ngữ cảnh.

Bước 4 – Cập nhật dữ liệu từ các component lồng nhau

Trong bước này, bạn sẽ sử dụng ngữ cảnh và Hook useReducer để tạo dữ liệu động mà các component lồng nhau có thể sử dụng và cập nhật. Bạn sẽ cập nhật component SaladItem của mình để thiết lập dữ liệu SaladSummary sẽ sử dụng và hiển thị. Bạn cũng sẽ đặt các trình cung cấp ngữ cảnh bên ngoài component gốc. Đến cuối bước này, bạn sẽ có một ứng dụng có thể sử dụng và cập nhật dữ liệu trên một số component và bạn sẽ có thể thêm nhiều trình cung cấp ngữ cảnh ở các cấp độ khác nhau của một ứng dụng.

Tại thời điểm này, ứng dụng của bạn đang hiển thị dữ liệu người dùng trên nhiều component, nhưng nó thiếu bất kỳ sự tương tác nào của người dùng. Trong bước trước, bạn đã sử dụng ngữ cảnh để chia sẻ một phần dữ liệu, nhưng bạn cũng có thể chia sẻ một tập hợp dữ liệu, bao gồm cả các hàm. Điều đó có nghĩa là bạn có thể chia sẻ dữ liệu và cũng có thể chia sẻ hàm để cập nhật dữ liệu.

Trong ứng dụng của bạn, mỗi SaladItem cần cập nhật danh sách được chia sẻ. Sau đó, component SaladSummary của bạn sẽ hiển thị các mục mà người dùng đã chọn và thêm nó vào danh sách. Vấn đề là các component này không phải là con cháu trực tiếp, vì vậy bạn không thể truyền dữ liệu và các hàm cập nhật dưới dạng các prop được. Nhưng chúng lại chia sẻ với một cha chung là: SaladMaker.

Một trong những điểm khác biệt lớn giữa ngữ cảnh và các giải pháp quản lý state khác như Redux là ngữ cảnh không nhằm mục đích trở thành một nơi lưu trữ trung tâm. Bạn có thể sử dụng nó nhiều lần trong một ứng dụng và khởi tạo nó ở cấp gốc hoặc sâu trong cây component. Nói cách khác, bạn có thể dàn trải các ngữ cảnh của mình trong toàn bộ ứng dụng, tạo ra các bộ sưu tập dữ liệu tập trung mà không lo xung đột.

Để giữ cho ngữ cảnh được tập trung, hãy tạo Providers để gộp cha được chia sẻ gần nhất khi có thể. Trong trường hợp này, điều đó có nghĩa là, thay vì thêm một ngữ cảnh khác vào App, bạn sẽ thêm ngữ cảnh trong component SaladMaker.

Mở file SaladMaker.js ra, sau đó, tạo và xuất (export) một ngữ cảnh mới được gọi là SaladContext:

import

{

createContext

}

from

'react'

;

import

{

createUseStyles

}

from

'react-jss'

;

import

SaladBuilder

from

'../SaladBuilder/SaladBuilder'

;

import

SaladSummary

from

'../SaladSummary/SaladSummary'

;

const

useStyles

=

createUseStyles

(

{

wrapper

:

{

textAlign

:

'center'

,

}

}

)

;

export

const

SaladContext

=

createContext

(

)

;

export

default

function

SaladMaker

(

)

{

const

classes

=

useStyles

(

)

;

return

(

<

>

<

h1 className

=

{

classes

.

wrapper

}

>

<

span role

=

"img"

aria

-

label

=

"salad"

>

🥗

<

/

span

>

Build Your Custom Salad

!

<

span role

=

"img"

aria

-

label

=

"salad"

>

🥗

<

/

span

>

<

/

h1

>

<

SaladBuilder

/

>

<

SaladSummary

/

>

<

/

>

)

}

Trong bước trước, bạn đã tạo một component riêng biệt cho ngữ cảnh của mình, nhưng trong trường hợp này, bạn đang tạo nó trong cùng một tệp mà bạn đang sử dụng nó. Vì User dường như không liên quan trực tiếp đến App, nên có thể có ý nghĩa hơn nếu giữ chúng tách biệt. Tuy nhiên, vì mã SaladContext được gắn chặt với component SaladMaker, nên việc giữ chúng lại với nhau sẽ tạo ra mã dễ đọc hơn.

Ngoài ra, bạn có thể tạo một ngữ cảnh chung chung hơn được gọi là ngữ cảnh OrderContext mà bạn có thể sử dụng lại trên nhiều component. Trong trường hợp đó, bạn cần tạo một component riêng biệt. Còn bây giờ, hãy giữ chúng lại với nhau. Bạn luôn có thể cấu trúc lại sau nếu bạn quyết định chuyển sang một mẫu khác.

Trước khi bạn thêm Provider, hãy suy nghĩ về dữ liệu mà bạn muốn chia sẻ. Bạn sẽ cần một mảng các mục và một hàm để thêm các mục. Không giống như các công cụ quản lý state tập trung khác, ngữ cảnh không xử lý các cập nhật cho dữ liệu của bạn. Nó chỉ giữ dữ liệu để sử dụng sau này. Để cập nhật dữ liệu, bạn sẽ cần sử dụng các công cụ quản lý state khác như Hook. Nếu bạn đang thu thập dữ liệu cho cùng một component, bạn sẽ sử dụng Hook useState hoặc useReducer. Nếu bạn chưa quen với các Hook này, hãy xem Cách quản lý state bằng Hook trên các component.

Hook useReducer là một sự phù hợp tốt vì bạn sẽ cần phải cập nhật trạng thái gần đây nhất trên tất cả các hành động.

Tạo một hàm reducer để thêm một mục mới vào một mảng state, sau đó sử dụng Hook useReducer để tạo một mảng salad và một hàm setSalad:

import

{

useReducer

,

createContext

}

from

'react'

;

import

{

createUseStyles

}

from

'react-jss'

;

import

SaladBuilder

from

'../SaladBuilder/SaladBuilder'

;

import

SaladSummary

from

'../SaladSummary/SaladSummary'

;

const

useStyles

=

createUseStyles

(

{

wrapper

:

{

textAlign

:

'center'

,

}

}

)

;

export

const

SaladContext

=

createContext

(

)

;

function

reducer

(

state

,

item

)

{

return

[

...

state

,

item

]

}

export

default

function

SaladMaker

(

)

{

const

classes

=

useStyles

(

)

;

const

[

salad

,

setSalad

]

=

useReducer

(

reducer

,

[

]

)

;

return

(

<

>

<

h1 className

=

{

classes

.

wrapper

}

>

<

span role

=

"img"

aria

-

label

=

"salad"

>

🥗

<

/

span

>

Build Your Custom Salad

!

<

span role

=

"img"

aria

-

label

=

"salad"

>

🥗

<

/

span

>

<

/

h1

>

<

SaladBuilder

/

>

<

SaladSummary

/

>

<

/

>

)

}

Bây giờ bạn đã có một component chứa dữ liệu salad bạn muốn chia sẻ, một hàm được gọi là setSalad để cập nhật dữ liệu và SaladContext để chia sẻ dữ liệu. Lúc này, bạn cần kết hợp chúng lại với nhau.

Để kết hợp, bạn cần tạo một Provider. Vấn đề là ở chỗ Provider chỉ mang một giá trị đơn value làm prop thôi, vậy nên bạn không thể truyền đồng thời cả salad và setSalad, cho nên bạn sẽ cần kết hợp chúng thành một đối tượng và truyền đối tượng dưới dạng value:

import

{

useReducer

,

createContext

}

from

'react'

;

import

{

createUseStyles

}

from

'react-jss'

;

import

SaladBuilder

from

'../SaladBuilder/SaladBuilder'

;

import

SaladSummary

from

'../SaladSummary/SaladSummary'

;

const

useStyles

=

createUseStyles

(

{

wrapper

:

{

textAlign

:

'center'

,

}

}

)

;

export

const

SaladContext

=

createContext

(

)

;

function

reducer

(

state

,

item

)

{

return

[

...

state

,

item

]

}

export

default

function

SaladMaker

(

)

{

const

classes

=

useStyles

(

)

;

const

[

salad

,

setSalad

]

=

useReducer

(

reducer

,

[

]

)

;

return

(

<

SaladContext

.

Provider value

=

{

{

salad

,

setSalad

}

}

>

<

h1 className

=

{

classes

.

wrapper

}

>

<

span role

=

"img"

aria

-

label

=

"salad"

>

🥗

<

/

span

>

Build Your Custom Salad

!

<

span role

=

"img"

aria

-

label

=

"salad"

>

🥗

<

/

span

>

<

/

h1

>

<

SaladBuilder

/

>

<

SaladSummary

/

>

<

/

SaladContext

.

Provider

>

)

}

Lưu file SaladMaker.js lại. Cũng giống như Navigation, nó có vẻ không cần thiết để tạo ra một ngữ cảnh khi SaladSummary nằm trong component tương tự như ngữ cảnh. Việc truyền salad như một prop là hoàn toàn hợp lý, nhưng bạn có thể sẽ cần cấu trúc lại nó sau đó. Sử dụng ngữ cảnh ở đây sẽ giúp giữ thông tin cùng ở một nơi duy nhất.

Tiếp theo, ta vào component SaladItem và kéo hàm setSalad ra khỏi ngữ cảnh.

Mở SaladItem.js ra, import ngữ cảnh từ SaladMaker, sau đó kéo hàm setSalad ra bằng cách sử dụng hàm hủy. Thêm sự kiện nhấp chuột vào nút sẽ gọi hàm setSalad. Vì bạn muốn người dùng có thể thêm một sản phẩm nhiều lần, nên bạn cũng cần tạo một id duy nhất cho từng mục để hàm map có thể chỉ định một key duy nhất:

import

{

useReducer

,

useContext

}

from

'react'

;

import

PropTypes

from

'prop-types'

;

import

{

createUseStyles

}

from

'react-jss'

;

import

UserContext

from

'../User/User'

;

import

{

SaladContext

}

from

'../SaladMaker/SaladMaker'

;

const

useStyles

=

createUseStyles

(

{

...

}

)

;

const

reducer

=

key

=>

key

+

1

;

export

default

function

SaladItem

(

{

image

,

name

}

)

{

const

classes

=

useStyles

(

)

;

const

{

setSalad

}

=

useContext

(

SaladContext

)

const

user

=

useContext

(

UserContext

)

;

const

favorite

=

user

.

favorites

.

includes

(

name

)

;

const

[

id

,

updateId

]

=

useReducer

(

reducer

,

0

)

;

function

update

(

)

{

setSalad

(

{

name

,

id

:

`

${

name

}

-

${

id

}

`

}

)

updateId

(

)

;

}

;

return

(

<

div className

=

{

classes

.

wrapper

}

>

<

h3

>

{

name

}

<

/

h3

>

<

span className

=

{

classes

.

favorite

}

aria

-

label

=

{

favorite

?

'Favorite'

:

'Not Favorite'

}

>

{

favorite

?

'😋'

:

''

}

<

/

span

>

<

button className

=

{

classes

.

add

}

onClick

=

{

update

}

>

<

span className

=

{

classes

.

image

}

role

=

"img"

aria

-

label

=

{

name

}

>

{

image

}

<

/

span

>

<

/

button

>

<

/

div

>

)

}

...

Để tạo id duy nhất, bạn sẽ sử dụng Hook useReducer để tăng giá trị trên mỗi lần nhấp chuột. Đối với lần nhấp đầu tiên, id sẽ là 0; thứ hai sẽ là 1, cứ như vậy. Bạn sẽ không bao giờ hiển thị giá trị này cho người dùng; điều này sẽ chỉ tạo ra một giá trị duy nhất cho hàm ánh xạ sau này.

Sau khi tạo id duy nhất, bạn đã tạo một hàm được gọi là update để tăng id và gọi setSalad. Cuối cùng, bạn gắn hàm vào nút bằng prop onClick.

Lưu file lại. Bước cuối cùng là kéo dữ liệu động từ ngữ cảnh trong SaladSummary.

Mở SaladSummary.js ra, import component SaladContext vào, sau đó lấy dữ liệu salad ra bằng cách sử dụng hàm hủy. Thay thế các mục danh sách được mã hóa cứng bằng một hàm ánh xạ salad, chuyển đổi các đối tượng thành các phần tử <li>. Hãy chắc chắn sử dụng id như key:

import

{

useContext

}

from

'react'

;

import

{

createUseStyles

}

from

'react-jss'

;

import

{

SaladContext

}

from

'../SaladMaker/SaladMaker'

;

const

useStyles

=

createUseStyles

(

{

...

}

)

;

export

default

function

SaladSummary

(

)

{

const

classes

=

useStyles

(

)

;

const

{

salad

}

=

useContext

(

SaladContext

)

;

return

(

<

div className

=

{

classes

.

wrapper

}

>

<

h2

>

Your Salad

<

/

h2

>

<

ul className

=

{

classes

.

list

}

>

{

salad

.

map

(

(

{

name

,

id

}

)

=>

(

<

li key

=

{

id

}

>

{

name

}

<

/

li

>

)

)

}

<

/

ul

>

<

/

div

>

)

}

Lưu file lại và quay lại trang web ta sẽ làm được như hình dưới đây:

Thêm các món salad

Lưu ý cách ngữ cảnh cung cấp cho bạn khả năng chia sẻ và cập nhật dữ liệu trong các component khác nhau. Ngữ cảnh không tự cập nhật các mục, nhưng nó cung cấp cho bạn một cách để sử dụng Hook useReducer trên nhiều component. Ngoài ra, bạn cũng có thể tự do đặt ngữ cảnh thấp hơn trong cây. Có vẻ như tốt nhất là luôn giữ ngữ cảnh ở gốc, nhưng bằng cách giữ ngữ cảnh thấp hơn, bạn không phải lo lắng về state không sử dụng vẫn tồn tại trong khu vực lưu trữ trung tâm. Ngay sau khi bạn ngắt kết nối một component, dữ liệu sẽ biến mất. Đó có thể là một vấn đề nếu bạn muốn lưu dữ liệu, nhưng trong trường hợp đó, bạn chỉ cần nâng ngữ cảnh lên mức gốc cao hơn.

Một lợi thế khác của việc sử dụng ngữ cảnh thấp hơn trong cây ứng dụng của bạn là bạn có thể sử dụng lại ngữ cảnh mà không lo xung đột. Giả sử bạn có một ứng dụng lớn hơn có máy làm bánh mì sandwich và máy làm salad. Bạn có thể tạo một ngữ cảnh chung được gọi là OrderContext và sau đó bạn có thể sử dụng nó ở nhiều vị trí trong component của mình mà không cần lo lắng về xung đột dữ liệu hoặc tên. Nếu bạn có một SaladMaker và một SandwichMaker, cây sẽ trông giống như sau:

| App
  | Salads
    | OrderContext
      | SaladMaker
  | Sandwiches
    | OrderContext
      | SandwichMaker

Ở đây OrderContext xuất hiện hai lần, nhưng điều này không sao cả vì Hook useContext sẽ tìm kiếm Provider gần nhất.

Trong bước này, bạn đã chia sẻ và cập nhật dữ liệu bằng cách sử dụng ngữ cảnh. Bạn cũng đã đặt ngữ cảnh bên ngoài phần tử gốc để nó gần với các component cần thông tin mà không làm lộn xộn component gốc. Cuối cùng, bạn đã kết hợp ngữ cảnh với các Hook quản lý state để tạo dữ liệu động và có thể truy cập trên một số component.

Phần kết luận

Ngữ cảnh là một công cụ mạnh mẽ và linh hoạt cung cấp cho bạn khả năng lưu trữ và sử dụng dữ liệu trên một ứng dụng. Nó cung cấp cho bạn khả năng xử lý dữ liệu phân tán bằng các công cụ tích hợp mà không yêu cầu bất kỳ cài đặt hoặc cấu hình bổ sung nào của bên thứ ba.

Việc tạo ngữ cảnh có thể sử dụng lại rất quan trọng trên nhiều component chung, chẳng hạn như biểu mẫu cần truy cập dữ liệu trên các phần tử hoặc chế độ xem tab cần ngữ cảnh chung cho cả tab và màn hình. Bạn có thể lưu trữ nhiều loại thông tin trong các ngữ cảnh bao gồm chủ đề, dữ liệu biểu mẫu, thông báo cảnh báo, v.v. Ngữ cảnh cho phép bạn tự do xây dựng các component có thể truy cập dữ liệu mà không cần lo lắng về cách truyền dữ liệu qua các component trung gian hoặc cách lưu trữ dữ liệu trong một kho lưu trữ mà không làm cho kho trở lên quá lớn.