异步 store
Valtio 天然提供了对于异步 store 的支持。store 中的属性只要是 Promise
类型,那么在生成 store 的快照的时候,Valtio 就会异步处理这些值。而且这些异步的属性是可以使用 React 19 中提供的 use
来获取的,并且在读取这些异步属性的值的时候,如果组件使用了 Suspend
组件包裹,那么还可以有效的利用 Suspend
组件提供的功能。
例如以下是一个使用 fetch
异步获取数据的简单示例。
const store = proxy({
book: fetch(bookUrl).then((book) => book.json()),
});
const Book = () => {
const state = useSnapshot(store);
return <div>{use(state.book).title}</div>;
};
const App = () => {
return (
<Suspense fallback={<div>Loading...</div>}>
<Book />
</Suspense>
);
};
在使用异步操作的时候,useSnapshot
与 useTransition
搭配使用会出现问题,这是由于 useSnapshot
的设计影响的,要解决这个问题,可以使用 use-valtio
库提供的 useValtio
Hook 来代替 useSnapshot
。具体使用可以参考 Valtio 的使用一节。
刷新异步 store 中的属性
首先需要明确的一点是,虽然被称为异步 store,但只是这个 store 中的属性保存的是一个 Promise 类型的值,而不是一个方法。所以无论何时,在 store 的属性中保存的都应该是一个已经被 resolve
以后的 Promise 值。换句话说,对于这个值的刷新,并不在存储这个 Promise 值的属性本身,而是在其他的位置。
按照这样的思路,刷新这个异步 store 中的类型为 Promise 的属性,实际上就可以通过为其赋予一个新的 Promise 值来实现。z 最经典的示例就是将异步过程定义为一个 action,在需要的位置调用这个 action 即可。
export const booksStore = proxy({
books: [] as Book[] | Promise<Book[]>,
});
export const fetchBooks = async () => {
const response = await fetch("/api/books");
const books = await response.json();
booksStore.books = books;
};
在上面这个示例中,在任何位置只需要调用 fetchBooks
这个 action 函数,就可以立刻刷新 bookStore.books
中的 Promise 值,从而实现异步数据的更新。