Suspense и использованию этих промисов.У меня получилось следующее API, для экшенов добавляется параметр
deferred, и появляется новый компонент Await, в который и передается соответствующий экшен:
const deferredAction = declareAction({
name: 'deferred',
async fn() {
await sleep(1000);
return { data: 'ok' };
},
deferred: true,
});
const Page = () => {
return (
<Suspense
fallback={<div>Loading...</div>}
>
<Await
action={deferredAction}
error={(error) => <div>Error: {error.message}</div>}
>
{(data) => <DataCmp data={`Response: ${data.data}`} />}
</Await>
</Suspense>
);
};
Page.actions = [deferredAction];
Задача
Await компонента - выкидывать промис соответствующего полученному экшену Deferred объекта, до его резолва или реджекта, и код получается достаточно простой, минимальный пример без обработки ошибок, с использованием паттерна render props:
const Await = ({ action, children }) => {
const deferred = deferredMap.get(action.name)
if (deferred.isResolved()) {
return children(deferred.resolveData)
}
throw deferred.promise
}
В этом примере deferredMap на сервере обычный
new Map(), а на клиенте объект который смотрит в window.DEFERRED_MAP, оба варианта имплементируют один и тот же интерфейс, что делает компонент Await универсальным.Все остальное за нас делает React.