Đối với những bạn đã biết và sử dụng React & React Native thì việc dùng kèm 1 thư viện để quản lý state như Redux là điều rất phổ biến. Mình cũng sử dụng React được một thời gian tuy nhiên thời gian đầu mình hay sử dụng theo hướng thuần - không sử dụng thư viện riêng biệt để quản lý state (lấy Redux làm đại diện). Trong bài viết này mình sẽ chia sẻ và trao đổi một số tips khi làm việc với React & React Native theo hướng thuần.
Lưu ý:
- Bài viết chỉ đơn giản là chia sẻ và trao đổi, không khuyến khích các bạn bỏ Redux, do vậy hãy giữ tư tưởng mở.
- Để hiểu rõ bài viết thì nên có kiến thức về React, đối với những bạn mới tiếp xúc với React / React Native nếu gặp khó khăn trong việc học Redux (phải học trước một đống thứ như React, JSX, Babel, Webpack, Native Component & Native Module dẫn đến ngợp), thì hy vọng bài viết này sẽ cung cấp cho các bạn 1 cái gì đó để thoải mái hơn và vững vàng hơn trước khi học những cái mới.
- Luồng dữ liệu
pass data down, pass event up
. làm cho phải truyền data và function qua props khá nhiều, khi app phức tạp dần lên thì rất khó quản lý. (Vấn đề quản lý dữ liệu giữ component cha - con ) - Truyền qua props thì các component không cùng cây thư mục rất khó giao tiếp (Vấn đề giao tiếp giữa các component)
- Vấn đề đồng bộ dữ liệu giữa các component khi 1 thông tin chung thay đổi.
Giải pháp? Redux ? Redux giải quyết các vấn đề trên khá OK, tuy nhiên nó kèm theo một đống thứ khác nữa khiến việc học và vận dụng trở nên khó khăn. Bài viết sẽ cung cấp 2 hướng tiếp cận và 1 loạt các tool sử dụng trong các trường hợp.
Global Store là chính tư tưởng của Redux, tuy nhiên nó có thể được thực hiện chỉ cần sử dụng React.
context
là một phần ít được đề cập trong React. Sử dụng context
thì có thể giao tiếp giữa component cha với component con mà không cần pass qua các component ở giữa. Thông tin về context
các bạn có thể đọc thêm ở đây. Luồng làm việc với context
sẽ như sau:
- Khai báo context ở Component to nhất (Tạm gọi là Root )
- Tạo 1 method ở Root có thể get/set
state
. - Truyền method đó qua
context
- Khai báo nhận
context
ở các Component con (Tạm gọi là Child). Child chỉ việc sử dụng method này để get/setstate
của Root. - Mọi thông tin cần thiết đều lưu vào
state
của Root. Khi có thay đổi thì Root sẽ render lại dẫn đến UI được cập nhật một cách tự động.
Tham khảo Gist: https://gist.github.com/lequanghuylc/2d9c0ff12c6ac64557c0acb4a0987ff1
Vấn đề với việc sử dụng context
: Bản thân Facebook cũng không khuyến khích sử dụng context, vì nó có thể thay đổi trong tương lai, cũng như nếu sử dụng không chuẩn sẽ rất rối. Tuy nhiên chúng ta hãy lướt qua các thư viện nổi tiếng:
react-redux
sử dụngcontext
(không đáng kể)react-router
sử dụngcontext
react-navigation
sử dụngcontext
- Nhiều thư viện về UI sử dụng
context
Mặc dù không nhiều tuy nhiên context
vẫn được sử dụng. Vấn đề là cách sử dụng thế nào mà thôi. Mặt khác gói trong Root và Child thì sẽ không làm việc trực tiếp với context
(this.store), nếu context
bị loại bỏ ở React trong các phiên bản sau, chúng ta hoàn toàn có thể cập nhật lại 2 file Child và Root (bằng giải pháp tiếp dưới đây) là xong.
Giải pháp này hoàn toàn có thể thay thế context
, ngoài ra còn vượt trội hơn khá nhiều khi có thể truy cập được ngoài phạm vi React, giữa các React Application với nhau (trường hợp website hỗn hợp React và các cách xây dựng UI khác).
Luồng làm việc với export method setState
sẽ như sau:
- Tạo 1 BaseComponent
- Thiết lập biến
static
choBaseComponent
- Trong
componentWillMount
, gán biếnstatic
đó vào một function mới tạo để có thể get/set state - Viết lại biến
static
để có thể dùng với nhiều instance. (Có thể quản lý thông qua id) - Khi tạo các component thì extends từ
BaseComponent
, sau đó có thể import và gọi trực tiếp biếnstatic
để get/set state cho component (dĩ nhiên là component đó phải được mount vào rồi)
Bằng với cách này, chúng ta có thể quản lý mọi component ở bất cứ đâu. Nếu theo hướng Global Store, thì chỉ cần quản lý component Root là đủ.
Tham khảo gist: https://gist.github.com/lequanghuylc/128ad8d8822d00c632a26e2737a75b81
Example app về phần này mình đang hoàn thiện và sẽ cập nhật sau.
service
đơn giản là cách gọi một hoạt động được thực hiện không liên quan đến UI (headless) và đảm nhận một công việc gì đó, nôm na là sẽ viết riêng phần xử lý logic của app ra bên ngoài và trả dữ liệu cho UI để hiển thị.
Luồng hoạt động của service:
- Không xử lý logic trong Component
- Tạo một
service module
có thể chạy độc lập, headless.service
dùng để làm tính năng cho app (ví dụ như wrapper của server API, socket, local DB, thực hiện một số function native). - Bên component lấy kết quả từ API trả về để cập nhật UI
- Viết
event listener
choservice
, để cập nhật dữ liệu ngay cho UI
1 ví dụ khá tiêu biểu cho việc sử dụng service
là firebase
. Như dùng firebase
thì login xong nó cũng không trả về token j cho mình, chỉ biết là đã login, khi nào hoạt động gì cũng sử dụng qua function của nó. Tất cả những dữ liệu đều được gói gọn bên trong và chỉ trả về ra bên ngoài những gì cần thiết. Khi firebase database có dữ liệu thay đổi, thì nó cũng cung cấp 1 vài hàm để xử lý dữ liệu mới kịp thời.
Một ví dụ về cách cấu tạo 1 service, sử dụng class
và state
để quen thuộc với React
class ServiceA {
constructor() {
this.syncData();
}
state = {};
// lưu 1 state trực tiếp bằng cách this.state.something = "something"
syncData = () => {
// sync data với local khi mở lại app nếu cần
}
login = (id, pass) => {
// call api or something
}
logout = () => {
}
onLoggedOut = ( callback ) => {
// listener dùng để chạy callback khi đã logout
}
}
// export với new để sử dụng singleton
export default new ServiceA();
Ngoài việc dùng event listener
trong service
, bạn có thể sử dụng trực tiếp để giao tiếp giữa các component với nhau (VD: Chuyển modal alert từ dạng component sang dạng function). Tham khảo react-native-event-listeners và js-events-listener
Bài viết mới dừng lại ở lý thuyết, mình sẽ cập nhật example code và giải thích sâu hơn sau nếu được. Tuy nhiên cũng khá rõ ràng để có thể suy nghĩ và xem xét rồi.
Vậy so với Redux thì sao?
Như đã nói ở trước Redux ngoài việc giải quyết các vấn đề hay gặp của React thì còn một số thứ khác nữa. Nó đề cập nhiều đến các vấn đề như architecture (từ Flux
cho đến Redux
), các khái niệm mới khi implement (action
& reducer
), và ecosystem để dev theo the Redux way
. So với bài viết thì chỉ đơn giản cung cấp cho bạn 1 vài công cụ để có thể làm được nhiều thứ hơn với React thuần. Bạn có thể sử dụng tự do theo ý thích. (Thực tế sử dụng Redux
không tốt cũng rất dễ rối do số lượng action
và reducer
ngày càng tăng. Điều quan trọng vẫn là cách tổ chức của dev).
Hãy thử tạm quên Redux
đi và suy nghĩ về các công cụ trên :)