Cộng đồng React đã chứng kiến một số các mô hình khác nhau quản lý state xuất hiện trong vài năm qua. Chúng bao gồm các API đơn giản như là setState
đến các thư viện bên thứ 3 như là Redux và MobX và ContextAPI được cập nhập gần đây
Unstated là một thư viện mới từ @jamiebuilds mà đã đạt được một số thích thú trong cộng đồng. Nó tận dụng sức mạnh của React ContextAPI để làm cho việc quán lý state trở nên vô cùng đơn giản. Đơn giản như thế nào? Khẩu hiệu của unstated là
State so simple, it goes without saying.
API là tương đối nhỏ và bạn có thể cài đặt và chạy nó trong vài phút. Đây là điểm tích cực lớn trong một thế giới nơi các giải pháp quản lý state bên thứ 3 mất thời gian đáng kể để tìm hiểu.
React có giải pháp quản lý state của chính nó, setState
. Nó là một API đơn giản và giải pháp tuyệt vời cho hầu hết các dự án. Hầu hết các Developer sẽ học và sử dụng setState
trước khi sử dụng một cái gì đó.
Nhưng chắc chắn bạn sẽ gặp một vài vấn đề, thường là trong trường hợp với các object state lớn và xử lý các event làm cho các component trở nên phức tạp và bẩn thỉu, bên cạch đó là việc truyền state xuống các component con sử dụng prop
Điều này dẫn đến chúng ta phải sử dụng các thư viện bên thứ 3 như là Redux và Mobx, giúp chúng ta quản lý các state, tách rời việc phân cấp giữa các component, trong khi vẫn cho phép các thành phần đăng ký để nhận bất kỳ các thay đổi nào của state. Nhờ đó chúng ta có thể giải quyết được hầu hết các vấn đề của setState
.
Nhưng hầu hết các thư viện nó đều có ưu điểm vào nhược điểm. Khi chúng ta sử dụng các thư viện trên như Redux, nó làm cho source code trở nên dài dòng. Số file mà chúng ta cần sử dụng, tương tác, thay đổi tương đối lớn và gây khó hiểu cho người mới học.
Nào chúng ta hãy cùng nhau tìm hiểu về unstated.
Unstated xây dựng dựa trên 3 ý tưởng chính / component
Container
Về khái niệm cơ bản, bạn có thể coi container như một store (lưu trữ)
Container là một class đơn giản trông giống như React Component nhưng chỉ có các phần liên quan tới state.
BookContainer.js
import { Container } from 'unstated' class BookContainer extends Container { state = { books: [], booksVisible: false } addBook = book => { const books = [...this.state.books, book] this.setState({ books }) } toggleVisibility = () => { this.setState({ booksVisible: !this.state.booksVisible }) } } export { BookContainer }
Subscribe
Subscribe là cách bạn truyền state từ container đến các component. Nó sẽ hoạt động giống như cách state hoạt động. Ví dụ khi state thay đổi các component được render lại nhưng bạn có thể cũng cần gọi lại các phương thức trong Container.
import { Subscribe } from 'unstated' import { BookContainer } from './BookContainer' <Subscribe to={[BookContainer]}> { bookStore => { const { state: { books, booksVisible } } = bookStore { booksVisible && books.map((book, index) => ( <div> <p>{book.name}</p> <p>{book.author}</p> </div> ) } } } </Subscribe>
Provider
Provider là nơi chúng ta chứa tất cả các instance nội bộ. Unstated Prodiver hoạt động giống như Redux hay Apollo Provider theo nghĩa là sử dụng bối cảnh một cách linh động giúp trừu tượng hoá API thành một cái gì đó rất dễ sử dụng trong các component
import { Provider } from 'unstated' import Main from './pathtomainentrypoint' const App = () => ( <Provider> <Main /> </Provider> )
Thêm nhiều container vào một component
Thứ tự mà bạn subscribe vào các container là thứ tự chúng ta có sẵn như các prop con
Ví dụ chúng ta có BookStore tồn tại nhưng cũng có một CounterStore. Chúng ta có thể sử dụng cả 2 như sau
<Subscribe to={[BookContainer, CounterContainer]}> { (bookStore, counterStore) => { // do stuff here } } </Subscribe>
Các phương thức Lifecycle
Làm thế nào để chúng ta có thể truy cập các phương thức Lifecycle nếu chúng ta chỉ truy cập đến các container trong render? Và làm thế nào hoạt động với các request bất đồng bộ?
- Đóng gói component của mình với các component khác mà có quyền truy cập container và truyền các phương thức vào trong như props để sử dụng chúng trong các phương thức Lifecycle
- Sử dụng async-wait gọi hàm
setState
nếu cần
Về cơ bản như sau
export default class ComeClass extends Component { render() { return ( <Provider> <Subscribe to={[BookContainer, CounterContainer, LocationsContainer]} > {(bookStore, counterStore, locationsStore) => ( <SomeContainer bookStore={bookStore} CounterContainer={CounterContainer} locationsStore={locationsStore} /> )} </Subscribe> </Provider> ); } }
SomeContainer component không chỉ là nới render ra UI nhưng cũng là nơi có thể truy cập các phương thức Lifecycle.
Sử dụng bất đồng bộ
Với Redux bạn có thể đã sử dụng Thunk, Sagas, hay thậm chí là Redux Observable để xử lý các hoạt động bất đồng bộ. Những công cụ này rất là tốt nhưng thực sự mà nói nó làm tăng thêm sự phức tạp, gây khó khăn cho người mới học và dẫn đến từ bỏ
Với thư viện này, không cần bất cứ plugin, middleware hay module bên thứ 3 để xử lý bất đồng bộ, bạn chỉ cần sử dụng fetch, axios hay thư viện nào mà bạn thích để xử lý xhr và tất cả đều hoạt động tốt