{"action":"created","comment":{"url":"https://api.github.com/repos/reactjs/rfcs/pulls/comments/226685502","pull_request_review_id":166573794,"id":226685502,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDIyNjY4NTUwMg==","diff_hunk":"@@ -0,0 +1,109 @@\n+\n+Start Date: 2018-10-19\n+- RFC PR: (leave this empty)\n+- React Issue: (leave this empty)\n+\n+# Summary\n+\n+`React.lazy` adds first-class support for code splitting components to React. It takes a module object and returns a special component type.\n+\n+# Basic example\n+\n+```js \n+import Input from './Input'; // Regular import\n+const Button = React.lazy(() => import('./Button')); // Dynamic import\n+\n+function Dialog() {\n+  // You can mix normal and lazy-loaded components in one tree\n+  return (\n+    <form>\n+      <Input />\n+      <Button />\n+    </form>\n+  );\n+}\n+```\n+\n+The first time `<Button />` is rendered, it would trigger the dynamic `import` which would start loading the code. When the `Button` code has loaded, React would resume rendering.\n+\n+Note that this **wouldn't** immediately render a spinner or an empty space instead of the `<Button />` like userland solutions would do today. Instead, the render would get *suspended*. You would have full control over how far above in the tree to put the loading indicator, as well as an opportunity to skip the indicator altogether on fast connections. This is a part of the \"Suspense\" feature umbrella. The RFC specifying how Suspense itself works exactly is not published yet, but you can find a demonstration in the [second half of this talk](https://reactjs.org/blog/2018/03/01/sneak-peek-beyond-react-16.html). Specifying the exact mechanics of Suspense is orthogonal to this RFC and doesn't need to block it.\n+\n+# Motivation\n+\n+Code splitting is one of the most effective ways to reduce the size of client-side code. It is achievable in React today but it requires either managing state manually or using a library that does it for you. However, even with either of these solutions, the typical user experience isn't ideal.\n+\n+Existing code splitting solutions tend to put the loading indicator (or a \"hole\") directly in place of the loaded component. As a result, you might end up with a cascade of spinners and \"holes\" as different leaf components are being loaded. Both spinners and \"holes\" make the loading sequence feel more janky, and cause unnecessary layout work for the browser, making the app load slower. They are hard to orchestrate and handle in a visually consistent way so often people don't use code splitting at all, or only reserve it for the top-level components. However, leaf components (e.g. a complex text input) benefit from code splitting too.\n+\n+The goal of this API is to make it easy to code split any particular component regardless of whether it's closer to the root or to the leaves. Adding code splitting to a component shouldn't require you to restructure your components or their data flow. The Suspense API (to be discussed in a separate later RFC) would let you declaratively specify where to display the loading indicator, and use it both for code splitting and data fetching. React would make sure that only intentional loading states are displayed, and that async component boundaries aren't creating visual noise in the app loading sequence.\n+\n+# Detailed design\n+\n+`React.lazy` accepts a Promise factory, and returns a new component type. When React renders that type for the first time, it triggers the Promise factory (thus, in case of dynamic `import`, starting the request). If the Promise is fulfilled, React reads the `.default` value from it (assuming the resolved value is a module object), and uses it as a component type for rendering. If the Promise is rejected, the rejection is handled in the same way as React normally handles errors (by letting the nearest error boundary handle it). After the code has loaded, React caches the Promise result. Next renders of the components with this type become synchronous and have no extra cost.\n+\n+## Why the `.default` Field?\n+\n+You might be wondering why it reads the `.default` field from the Promise result rather than, for example, assume that the Promise result _itself_ is a component type. There are two reasons.\n+\n+We propose to read `.default` automatically so that we can write code like this:\n+\n+```js\n+const Button = lazy(() => import('./Button'));\n+```\n+\n+and not like this:\n+\n+```js\n+// Annoying and confusing:\n+const Button = lazy(() => import('./Button').then(Button => Button.default));\n+// Named imports don't make this better:\n+const Button = lazy(() => import('./Button').then(Button => Button.Button));\n+```\n+\n+(Note this doesn't mean you're forced to use default exports for *all* your components. Even if you primarily use named exports, consider default exports to be \"async entry points\" into just the components you want to code split.)\n+\n+The second part of the question is why don't we still _allow_ passing something without a `.default` property?\n+\n+```js\n+// Why don't we want to support this though?\n+const Button = lazy(async () => {\n+  const Components = await import('./components');\n+  // Resolve to named export:\n+  return components.Button;\n+});\n+```\n+\n+We **intentionally** don't support this in the scope of this proposal. This gives React an opportunity to integrate more tightly with the module system on the server in the future. There are no proposed standards for this yet, but the new Suspense-capable React server renderer we'll soon be working on will benefit from having a chance to introspect the `import()` result directly (rather than just a component). For example, it could change a priority of a pending request for the `Button.js` module once it knows that a component of the `Button` type is going to be lazily rendered. We can't do this if we break the link between the module and the component. While this depends on future experimentation and standardization work, this design leaves more space for it. We can always remove this restriction later if it doesn't end up being beneficial. (That's also why the proposal doesn't support arbitrary Promises as component types.)\n+\n+### Named Exports\n+\n+While named exports aren't currently supported by this proposal, it doesn't exclude them in the future. For example:\n+\n+```js\n+// Not a part of this RFC but plausible in the future\n+const Button = lazy(() => import('./components'), components => components.Button);","path":"text/0000-lazy.md","position":83,"original_position":83,"commit_id":"cf3da2d484051e77a10498f09251726c4d1a0537","original_commit_id":"cf3da2d484051e77a10498f09251726c4d1a0537","user":{"login":"sebmarkbage","id":63648,"node_id":"MDQ6VXNlcjYzNjQ4","avatar_url":"https://avatars2.githubusercontent.com/u/63648?v=4","gravatar_id":"","url":"https://api.github.com/users/sebmarkbage","html_url":"https://github.com/sebmarkbage","followers_url":"https://api.github.com/users/sebmarkbage/followers","following_url":"https://api.github.com/users/sebmarkbage/following{/other_user}","gists_url":"https://api.github.com/users/sebmarkbage/gists{/gist_id}","starred_url":"https://api.github.com/users/sebmarkbage/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sebmarkbage/subscriptions","organizations_url":"https://api.github.com/users/sebmarkbage/orgs","repos_url":"https://api.github.com/users/sebmarkbage/repos","events_url":"https://api.github.com/users/sebmarkbage/events{/privacy}","received_events_url":"https://api.github.com/users/sebmarkbage/received_events","type":"User","site_admin":false},"body":"I think maybe we’ll try to warn against that pattern since it will break future work","created_at":"2018-10-19T15:20:49Z","updated_at":"2018-10-19T15:20:49Z","html_url":"https://github.com/reactjs/rfcs/pull/64#discussion_r226685502","pull_request_url":"https://api.github.com/repos/reactjs/rfcs/pulls/64","author_association":"COLLABORATOR","_links":{"self":{"href":"https://api.github.com/repos/reactjs/rfcs/pulls/comments/226685502"},"html":{"href":"https://github.com/reactjs/rfcs/pull/64#discussion_r226685502"},"pull_request":{"href":"https://api.github.com/repos/reactjs/rfcs/pulls/64"}},"in_reply_to_id":226683684},"pull_request":{"url":"https://api.github.com/repos/reactjs/rfcs/pulls/64","id":224289539,"node_id":"MDExOlB1bGxSZXF1ZXN0MjI0Mjg5NTM5","html_url":"https://github.com/reactjs/rfcs/pull/64","diff_url":"https://github.com/reactjs/rfcs/pull/64.diff","patch_url":"https://github.com/reactjs/rfcs/pull/64.patch","issue_url":"https://api.github.com/repos/reactjs/rfcs/issues/64","number":64,"state":"open","locked":false,"title":"React.lazy()","user":{"login":"gaearon","id":810438,"node_id":"MDQ6VXNlcjgxMDQzOA==","avatar_url":"https://avatars0.githubusercontent.com/u/810438?v=4","gravatar_id":"","url":"https://api.github.com/users/gaearon","html_url":"https://github.com/gaearon","followers_url":"https://api.github.com/users/gaearon/followers","following_url":"https://api.github.com/users/gaearon/following{/other_user}","gists_url":"https://api.github.com/users/gaearon/gists{/gist_id}","starred_url":"https://api.github.com/users/gaearon/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gaearon/subscriptions","organizations_url":"https://api.github.com/users/gaearon/orgs","repos_url":"https://api.github.com/users/gaearon/repos","events_url":"https://api.github.com/users/gaearon/events{/privacy}","received_events_url":"https://api.github.com/users/gaearon/received_events","type":"User","site_admin":false},"body":"### [View formatted RFC](https://github.com/reactjs/rfcs/blob/gaearon-patch-2/text/0000-lazy.md)\r\n\r\n**Note: I just wrote up the RFC. The semantics are designed by @sebmarkbage and @acdlite.** ","created_at":"2018-10-19T13:35:37Z","updated_at":"2018-10-19T15:20:49Z","closed_at":null,"merged_at":null,"merge_commit_sha":"fed7c49642d58e91f3ac753ca0bbef3ad028739b","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[{"id":771673915,"node_id":"MDU6TGFiZWw3NzE2NzM5MTU=","url":"https://api.github.com/repos/reactjs/rfcs/labels/CLA%20Signed","name":"CLA Signed","color":"ededed","default":false}],"milestone":null,"commits_url":"https://api.github.com/repos/reactjs/rfcs/pulls/64/commits","review_comments_url":"https://api.github.com/repos/reactjs/rfcs/pulls/64/comments","review_comment_url":"https://api.github.com/repos/reactjs/rfcs/pulls/comments{/number}","comments_url":"https://api.github.com/repos/reactjs/rfcs/issues/64/comments","statuses_url":"https://api.github.com/repos/reactjs/rfcs/statuses/cf3da2d484051e77a10498f09251726c4d1a0537","head":{"label":"reactjs:gaearon-patch-2","ref":"gaearon-patch-2","sha":"cf3da2d484051e77a10498f09251726c4d1a0537","user":{"login":"reactjs","id":6412038,"node_id":"MDEyOk9yZ2FuaXphdGlvbjY0MTIwMzg=","avatar_url":"https://avatars3.githubusercontent.com/u/6412038?v=4","gravatar_id":"","url":"https://api.github.com/users/reactjs","html_url":"https://github.com/reactjs","followers_url":"https://api.github.com/users/reactjs/followers","following_url":"https://api.github.com/users/reactjs/following{/other_user}","gists_url":"https://api.github.com/users/reactjs/gists{/gist_id}","starred_url":"https://api.github.com/users/reactjs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/reactjs/subscriptions","organizations_url":"https://api.github.com/users/reactjs/orgs","repos_url":"https://api.github.com/users/reactjs/repos","events_url":"https://api.github.com/users/reactjs/events{/privacy}","received_events_url":"https://api.github.com/users/reactjs/received_events","type":"Organization","site_admin":false},"repo":{"id":113273337,"node_id":"MDEwOlJlcG9zaXRvcnkxMTMyNzMzMzc=","name":"rfcs","full_name":"reactjs/rfcs","private":false,"owner":{"login":"reactjs","id":6412038,"node_id":"MDEyOk9yZ2FuaXphdGlvbjY0MTIwMzg=","avatar_url":"https://avatars3.githubusercontent.com/u/6412038?v=4","gravatar_id":"","url":"https://api.github.com/users/reactjs","html_url":"https://github.com/reactjs","followers_url":"https://api.github.com/users/reactjs/followers","following_url":"https://api.github.com/users/reactjs/following{/other_user}","gists_url":"https://api.github.com/users/reactjs/gists{/gist_id}","starred_url":"https://api.github.com/users/reactjs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/reactjs/subscriptions","organizations_url":"https://api.github.com/users/reactjs/orgs","repos_url":"https://api.github.com/users/reactjs/repos","events_url":"https://api.github.com/users/reactjs/events{/privacy}","received_events_url":"https://api.github.com/users/reactjs/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/reactjs/rfcs","description":"RFCs for changes to React","fork":false,"url":"https://api.github.com/repos/reactjs/rfcs","forks_url":"https://api.github.com/repos/reactjs/rfcs/forks","keys_url":"https://api.github.com/repos/reactjs/rfcs/keys{/key_id}","collaborators_url":"https://api.github.com/repos/reactjs/rfcs/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/reactjs/rfcs/teams","hooks_url":"https://api.github.com/repos/reactjs/rfcs/hooks","issue_events_url":"https://api.github.com/repos/reactjs/rfcs/issues/events{/number}","events_url":"https://api.github.com/repos/reactjs/rfcs/events","assignees_url":"https://api.github.com/repos/reactjs/rfcs/assignees{/user}","branches_url":"https://api.github.com/repos/reactjs/rfcs/branches{/branch}","tags_url":"https://api.github.com/repos/reactjs/rfcs/tags","blobs_url":"https://api.github.com/repos/reactjs/rfcs/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/reactjs/rfcs/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/reactjs/rfcs/git/refs{/sha}","trees_url":"https://api.github.com/repos/reactjs/rfcs/git/trees{/sha}","statuses_url":"https://api.github.com/repos/reactjs/rfcs/statuses/{sha}","languages_url":"https://api.github.com/repos/reactjs/rfcs/languages","stargazers_url":"https://api.github.com/repos/reactjs/rfcs/stargazers","contributors_url":"https://api.github.com/repos/reactjs/rfcs/contributors","subscribers_url":"https://api.github.com/repos/reactjs/rfcs/subscribers","subscription_url":"https://api.github.com/repos/reactjs/rfcs/subscription","commits_url":"https://api.github.com/repos/reactjs/rfcs/commits{/sha}","git_commits_url":"https://api.github.com/repos/reactjs/rfcs/git/commits{/sha}","comments_url":"https://api.github.com/repos/reactjs/rfcs/comments{/number}","issue_comment_url":"https://api.github.com/repos/reactjs/rfcs/issues/comments{/number}","contents_url":"https://api.github.com/repos/reactjs/rfcs/contents/{+path}","compare_url":"https://api.github.com/repos/reactjs/rfcs/compare/{base}...{head}","merges_url":"https://api.github.com/repos/reactjs/rfcs/merges","archive_url":"https://api.github.com/repos/reactjs/rfcs/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/reactjs/rfcs/downloads","issues_url":"https://api.github.com/repos/reactjs/rfcs/issues{/number}","pulls_url":"https://api.github.com/repos/reactjs/rfcs/pulls{/number}","milestones_url":"https://api.github.com/repos/reactjs/rfcs/milestones{/number}","notifications_url":"https://api.github.com/repos/reactjs/rfcs/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/reactjs/rfcs/labels{/name}","releases_url":"https://api.github.com/repos/reactjs/rfcs/releases{/id}","deployments_url":"https://api.github.com/repos/reactjs/rfcs/deployments","created_at":"2017-12-06T05:32:51Z","updated_at":"2018-10-19T15:17:38Z","pushed_at":"2018-10-19T14:57:43Z","git_url":"git://github.com/reactjs/rfcs.git","ssh_url":"git@github.com:reactjs/rfcs.git","clone_url":"https://github.com/reactjs/rfcs.git","svn_url":"https://github.com/reactjs/rfcs","homepage":null,"size":83,"stargazers_count":1531,"watchers_count":1531,"language":null,"has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":123,"mirror_url":null,"archived":false,"open_issues_count":30,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"forks":123,"open_issues":30,"watchers":1531,"default_branch":"master"}},"base":{"label":"reactjs:master","ref":"master","sha":"d362c5264d971c62ea0a9b9f184ff6fc5515a9c2","user":{"login":"reactjs","id":6412038,"node_id":"MDEyOk9yZ2FuaXphdGlvbjY0MTIwMzg=","avatar_url":"https://avatars3.githubusercontent.com/u/6412038?v=4","gravatar_id":"","url":"https://api.github.com/users/reactjs","html_url":"https://github.com/reactjs","followers_url":"https://api.github.com/users/reactjs/followers","following_url":"https://api.github.com/users/reactjs/following{/other_user}","gists_url":"https://api.github.com/users/reactjs/gists{/gist_id}","starred_url":"https://api.github.com/users/reactjs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/reactjs/subscriptions","organizations_url":"https://api.github.com/users/reactjs/orgs","repos_url":"https://api.github.com/users/reactjs/repos","events_url":"https://api.github.com/users/reactjs/events{/privacy}","received_events_url":"https://api.github.com/users/reactjs/received_events","type":"Organization","site_admin":false},"repo":{"id":113273337,"node_id":"MDEwOlJlcG9zaXRvcnkxMTMyNzMzMzc=","name":"rfcs","full_name":"reactjs/rfcs","private":false,"owner":{"login":"reactjs","id":6412038,"node_id":"MDEyOk9yZ2FuaXphdGlvbjY0MTIwMzg=","avatar_url":"https://avatars3.githubusercontent.com/u/6412038?v=4","gravatar_id":"","url":"https://api.github.com/users/reactjs","html_url":"https://github.com/reactjs","followers_url":"https://api.github.com/users/reactjs/followers","following_url":"https://api.github.com/users/reactjs/following{/other_user}","gists_url":"https://api.github.com/users/reactjs/gists{/gist_id}","starred_url":"https://api.github.com/users/reactjs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/reactjs/subscriptions","organizations_url":"https://api.github.com/users/reactjs/orgs","repos_url":"https://api.github.com/users/reactjs/repos","events_url":"https://api.github.com/users/reactjs/events{/privacy}","received_events_url":"https://api.github.com/users/reactjs/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/reactjs/rfcs","description":"RFCs for changes to React","fork":false,"url":"https://api.github.com/repos/reactjs/rfcs","forks_url":"https://api.github.com/repos/reactjs/rfcs/forks","keys_url":"https://api.github.com/repos/reactjs/rfcs/keys{/key_id}","collaborators_url":"https://api.github.com/repos/reactjs/rfcs/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/reactjs/rfcs/teams","hooks_url":"https://api.github.com/repos/reactjs/rfcs/hooks","issue_events_url":"https://api.github.com/repos/reactjs/rfcs/issues/events{/number}","events_url":"https://api.github.com/repos/reactjs/rfcs/events","assignees_url":"https://api.github.com/repos/reactjs/rfcs/assignees{/user}","branches_url":"https://api.github.com/repos/reactjs/rfcs/branches{/branch}","tags_url":"https://api.github.com/repos/reactjs/rfcs/tags","blobs_url":"https://api.github.com/repos/reactjs/rfcs/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/reactjs/rfcs/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/reactjs/rfcs/git/refs{/sha}","trees_url":"https://api.github.com/repos/reactjs/rfcs/git/trees{/sha}","statuses_url":"https://api.github.com/repos/reactjs/rfcs/statuses/{sha}","languages_url":"https://api.github.com/repos/reactjs/rfcs/languages","stargazers_url":"https://api.github.com/repos/reactjs/rfcs/stargazers","contributors_url":"https://api.github.com/repos/reactjs/rfcs/contributors","subscribers_url":"https://api.github.com/repos/reactjs/rfcs/subscribers","subscription_url":"https://api.github.com/repos/reactjs/rfcs/subscription","commits_url":"https://api.github.com/repos/reactjs/rfcs/commits{/sha}","git_commits_url":"https://api.github.com/repos/reactjs/rfcs/git/commits{/sha}","comments_url":"https://api.github.com/repos/reactjs/rfcs/comments{/number}","issue_comment_url":"https://api.github.com/repos/reactjs/rfcs/issues/comments{/number}","contents_url":"https://api.github.com/repos/reactjs/rfcs/contents/{+path}","compare_url":"https://api.github.com/repos/reactjs/rfcs/compare/{base}...{head}","merges_url":"https://api.github.com/repos/reactjs/rfcs/merges","archive_url":"https://api.github.com/repos/reactjs/rfcs/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/reactjs/rfcs/downloads","issues_url":"https://api.github.com/repos/reactjs/rfcs/issues{/number}","pulls_url":"https://api.github.com/repos/reactjs/rfcs/pulls{/number}","milestones_url":"https://api.github.com/repos/reactjs/rfcs/milestones{/number}","notifications_url":"https://api.github.com/repos/reactjs/rfcs/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/reactjs/rfcs/labels{/name}","releases_url":"https://api.github.com/repos/reactjs/rfcs/releases{/id}","deployments_url":"https://api.github.com/repos/reactjs/rfcs/deployments","created_at":"2017-12-06T05:32:51Z","updated_at":"2018-10-19T15:17:38Z","pushed_at":"2018-10-19T14:57:43Z","git_url":"git://github.com/reactjs/rfcs.git","ssh_url":"git@github.com:reactjs/rfcs.git","clone_url":"https://github.com/reactjs/rfcs.git","svn_url":"https://github.com/reactjs/rfcs","homepage":null,"size":83,"stargazers_count":1531,"watchers_count":1531,"language":null,"has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":123,"mirror_url":null,"archived":false,"open_issues_count":30,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"forks":123,"open_issues":30,"watchers":1531,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/reactjs/rfcs/pulls/64"},"html":{"href":"https://github.com/reactjs/rfcs/pull/64"},"issue":{"href":"https://api.github.com/repos/reactjs/rfcs/issues/64"},"comments":{"href":"https://api.github.com/repos/reactjs/rfcs/issues/64/comments"},"review_comments":{"href":"https://api.github.com/repos/reactjs/rfcs/pulls/64/comments"},"review_comment":{"href":"https://api.github.com/repos/reactjs/rfcs/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/reactjs/rfcs/pulls/64/commits"},"statuses":{"href":"https://api.github.com/repos/reactjs/rfcs/statuses/cf3da2d484051e77a10498f09251726c4d1a0537"}},"author_association":"MEMBER"}}
{"actor":{"display_login":"sebmarkbage"}}