Suspense
Suspense
React Suspense 全部涉及处理具有异步数据需求的视图之间的转换:
import { createCache } from "react-cache";
import { createResource } from "react-cache";
export let cache = createCache();
export let InvoiceResource = createResource((id) => {
return fetch(`/invoices/${id}`).then((response) => {
return response.json();
});
});
import cache from "./cache";
import InvoiceResource from "./InvoiceResource";
let Invoice = ({ invoiceId }) => {
let invoice = InvoiceResource.read(cache, invoiceId);
return <h1>{invoice.number}</h1>;
};
React 开始渲染(在内存中)。它打到了 InvoicesResource.read() 调用。该键的缓存(id 为键)将为空,因此它将调用我们提供给 createResource 的函数,从而触发异步获取。然后缓存将抛出我们返回的承诺(是的,我也从未考虑过抛出任何错误,但也有错误,但是如果需要可以抛出窗口。)抛出之后,不再执行任何代码。React 等待承诺解决。诺言解决。React 尝试再次渲染发票(在内存中)。它再次点击 InvoicesResource.read() 。这次数据位于缓存中,因此可以从 ApiResource.read() 同步返回我们的数据。React 将页面呈现到 DOM:
// the store and reducer
import { createStore } from "redux";
import { connect } from "react-redux";
let reducer = (state, action) => {
if (action.type === "LOADED_INVOICE") {
return {
...state,
invoice: action.data,
};
}
return state;
};
let store = createStore(reducer);
/////////////////////////////////////////////
// the action
function fetchInvoice(dispatch, id) {
fetch(`/invoices/${id}`).then((response) => {
dispatch({
type: "LOADED_INVOICE",
data: response.json(),
});
});
}
/////////////////////////////////////////////
// the component, all connected up
class Invoice extends React.Component {
componentDidMount() {
fetchInvoice(this.props.dispatch, this.props.invoiceId);
}
componentDidUpdate(prevProps) {
if (prevProps.invoiceId !== this.props.invoiceId) {
fetchInvoice(this.props.dispatch, this.props.invoiceId);
}
}
render() {
if (!this.props.invoice) {
return null;
}
return <h1>{invoice.number}</h1>;
}
}
export default connect((state) => {
return { invoices: state.invoices };
})(Invoices);
import React, { Suspense, Fragment, memo } from "react";
import { unstable_createResource } from "react-cache";
const Fetcher = unstable_createResource(() =>
fetch("https://jsonplaceholder.typicode.com/todos").then((r) => r.json())
);
const List = () => {
const data = Fetcher.read();
return (
<ul>
{data.map((item) => (
<li style={{ listStyle: "none" }} key={item.id}>
{item.title}
</li>
))}
</ul>
);
};
const App = () => (
<Fragment>
<h2 style={{ textAlign: "center" }}>{`React: ${React.version} Demo`}</h2>
<Suspense fallback={<div>Loading...</div>}>
<List />
</Suspense>
</Fragment>
);
const MemoApp = memo(App);
export default MemoApp;