我的用例大概如下。比如拿 book 的数据,可能组件有时候需要一个数组 books 、有时候是一个数据结构 book 。 然后, 拿 books 的条件是 book list id(一个书单 id 下面的所有书)和 user id(用户名下书),两者可以都有,或者有一个。
然后拿 book 的条件是 book id 。
我是应该抽象成useBooks(bookListId?:string, userId?: string)
和useBook(bookId:string)
两个 Hooks 还是直接返回一个 book store ,让组件自己拿数据? 这些 Hooks 感觉怎么怎么每次被调用时网络请求和数据更新的问题? 然后我还需要 createBook 、updateBook 之类的函数。
const { books, isLoading, createBook } = useBooks(xxx,xxx)
我之前用 swr 虽然感觉能凑合管理了,修改完数据就得 mutate 来刷新相关的 key 。但是总感觉不太舒服。
1
XCFOX 2023-12-23 14:11:19 +08:00 2
你可能需要使用 zustand 或者 valtio 等状态管理库。
我个人是喜欢用 class 封装成 controller 的,然后在组件内使用 valtio 的 proxy 和 useSnapshot 来使用。 ```ts class BookController { books: Record<string, Book> = {} async getBooks() { const books = await fetchBooks() books.forEach((book) => { this.books[book.id] = book }) } async createBook(book: Book) { // ... } async updateBook(id: string, book: Book) { // ... } } ``` 在组件内使用: ```tsx import { proxy, useSnapshot } from 'valtio' const YourComponent = () => { const controller = useMemo(() => proxy(new BookController()), []) const { books } = useSnapshot(controller) useEffect(() => { controller.getBooks() }, [controller]) const allBooks = Object.values(books) const oneBook = books['bookId'] return ( <div> {allBooks.map((book) => ( <div key={book.id}>{book.name}</div> ))} <button onClick={() => controller.createBook(yourBook)}>创建</button> </div> ) } ``` valtio: https://github.com/pmndrs/valtio zustand: https://github.com/pmndrs/zustand |
2
theprimone 363 天前
@XCFOX #1 Jotai 呢?
|
3
XCFOX 363 天前
@theprimone #2
状态管理主要解决的问题有: 1. 跨组件状态传递 2. 组织 actionsa ,比如 createBook 、updateBook zustand 强制在 create store 的时候组织 actions: https://docs.pmnd.rs/zustand/guides/updating-state valtio 很自由,可以用你最熟悉的 js 语法组织 actions: https://valtio.pmnd.rs/docs/how-tos/how-to-organize-actions Jotai 完全遵守 React Hooks 规则,本身没有组织 actions 的办法。需要使用 React 闭包 + useCallback 来封装 actions ,或者使用 Reducer 。 比如上面的 BookController 按 Jotai 的写法就会变成: ```ts import { atom } from 'jotai' const booksAtom = atom<Record<string, Book>>() function useBooks() { const [books, setBooks] = useAtom(booksAtom) const getBooks = useCallback(async () => { const books = await fetchBooks() setBooks((prevBooks) => { const nextBooks = { ...prevBooks } books.forEach((book) => { nextBooks[book.id] = book }) return nextBooks }) }, [setBooks]) const createBook = useCallback( async (book: Book) => { const newBook = await fetch('createBook', { method: 'POST', body: book }) setBooks((prevBooks) => ({ ...prevBooks, [newBook.id]: newBook })) }, [setBooks] ) const updateBook = useCallback( async (id: string, book: Book) => { // ... }, [setBooks] ) return { books, getBooks, createBook, updateBook } } ``` 因为我讨厌 useCallback 以及 Reducer ,所以不推荐 Jotai 。 |
4
theprimone 363 天前
@XCFOX #3 学习了,其实之前也看过这个 issue https://github.com/pmndrs/zustand/issues/483#issuecomment-876406137 一个组织整这么多状态管理也太秀了,不过后来看到个说法:
> Zustand 、Jotai 和 Valtio ,它们用起来分别非常像 Redux 、Recoil 和 MobX 之前有用过 zustand + immer 现在综合各方那我觉得还是这个方法比较合适啊 😂 更 React 一些 |