From c9102446eae68372f8e59cfae60c9c6183cb92ed Mon Sep 17 00:00:00 2001 From: Jess Telford Date: Thu, 2 May 2019 17:05:53 +1000 Subject: [PATCH] Generalise loading of multiple Suspense-aware components (#1078) --- .changeset/98042969/changes.json | 9 + .changeset/98042969/changes.md | 1 + packages/admin-ui/client/pages/Item/index.js | 267 ++++++++---------- packages/admin-ui/package.json | 3 +- packages/field-views-loader/index.js | 23 +- packages/fields/src/Controller.js | 26 +- .../src/types/Content/views/Controller.js | 11 +- packages/utils/package.json | 3 +- packages/utils/src/index.js | 32 +++ packages/utils/tests/utils.test.js | 124 ++++++++ 10 files changed, 324 insertions(+), 175 deletions(-) create mode 100644 .changeset/98042969/changes.json create mode 100644 .changeset/98042969/changes.md diff --git a/.changeset/98042969/changes.json b/.changeset/98042969/changes.json new file mode 100644 index 00000000000..b8f312ecf02 --- /dev/null +++ b/.changeset/98042969/changes.json @@ -0,0 +1,9 @@ +{ + "releases": [ + { "name": "@keystone-alpha/admin-ui", "type": "patch" }, + { "name": "@keystone-alpha/field-views-loader", "type": "patch" }, + { "name": "@keystone-alpha/fields", "type": "minor" }, + { "name": "@keystone-alpha/utils", "type": "minor" } + ], + "dependents": [] +} diff --git a/.changeset/98042969/changes.md b/.changeset/98042969/changes.md new file mode 100644 index 00000000000..d896a49d310 --- /dev/null +++ b/.changeset/98042969/changes.md @@ -0,0 +1 @@ +- Add a mechanism for loading multiple Suspense-aware components in parallel \ No newline at end of file diff --git a/packages/admin-ui/client/pages/Item/index.js b/packages/admin-ui/client/pages/Item/index.js index ac21d5b4768..714dab83477 100644 --- a/packages/admin-ui/client/pages/Item/index.js +++ b/packages/admin-ui/client/pages/Item/index.js @@ -6,14 +6,13 @@ import { Mutation, Query } from 'react-apollo'; import { withRouter } from 'react-router-dom'; import { withToastManager } from 'react-toast-notifications'; import memoizeOne from 'memoize-one'; -import isPromise from 'p-is-promise'; import { Container } from '@arch-ui/layout'; import { Button } from '@arch-ui/button'; import { AutocompleteCaptor } from '@arch-ui/input'; import { Card } from '@arch-ui/card'; import { gridSize } from '@arch-ui/theme'; -import { mapKeys, arrayToObject, omitBy } from '@keystone-alpha/utils'; +import { mapKeys, arrayToObject, omitBy, captureSuspensePromises } from '@keystone-alpha/utils'; import CreateItemModal from '../../components/CreateItemModal'; import DeleteItemModal from '../../components/DeleteItemModal'; @@ -186,15 +185,6 @@ const ItemDetails = withRouter( render() { const { adminPath, list, updateInProgress, itemErrors, item: savedData } = this.props; const { item, itemHasChanged } = this.state; - // we want to read all of the fields before reading the views individually - // note we want to _read_ before not just preload because the important thing - // isn't doing all the requests in parallel, that already happens - // what we're doing here is making sure there aren't a bunch of rerenders as - // each of the promises resolve - // this probably won't be necessary with concurrent mode/maybe just other react changes - // also, note that this is just an optimisation, it's not strictly necessary and it should - // probably be removed in the future because i'm guessing this will make performance _worse_ in concurrent mode - list.adminMeta.readViews(list.fields.map(({ views }) => views.Field)); return ( @@ -209,41 +199,39 @@ const ItemDetails = withRouter(
- {list.fields.map((field, i) => { - return ( - - {() => { - let [Field] = field.adminMeta.readViews([field.views.Field]); - - let onChange = useCallback( - value => { - this.setState(({ item: itm }) => ({ - item: { - ...itm, - [field.path]: value, - }, - itemHasChanged: true, - })); - }, - [field] - ); - return useMemo( - () => ( - - ), - [i, field, itemErrors[field.path], item[field.path]] - ); - }} - - ); - })} + {list.fields.map((field, i) => ( + + {() => { + const [Field] = field.adminMeta.readViews([field.views.Field]); + + let onChange = useCallback( + value => { + this.setState(({ item: itm }) => ({ + item: { + ...itm, + [field.path]: value, + }, + itemHasChanged: true, + })); + }, + [field] + ); + return useMemo( + () => ( + + ), + [i, field, itemErrors[field.path], item[field.path]] + ); + }} + + ))}