Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Split Timeout into separate Timeout and Placeholder primitives #12728

Closed
wants to merge 9 commits into from

Conversation

acdlite
Copy link
Collaborator

@acdlite acdlite commented May 1, 2018

I think this separation makes sense, if for no other reason than it helps with the mental model. A Timeout determines the threshold before a suspend "effect" turns into an error. A Placeholder is like an error boundary that pattern matches on those errors.

Depends on #12279. Opening this separately, since it's not needed for the basic functionality and it's debatable whether these are the right primitives.

acdlite and others added 9 commits May 1, 2018 13:36
Adds Timeout component. If a promise is thrown from inside a Timeout component,
React will suspend the in-progress render from committing. When the promise
resolves, React will retry. If the render is suspended for longer than the
maximum threshold, the Timeout switches to a placeholder state.

The timeout threshold is defined as the minimum of:
- The expiration time of the current render
- The `ms` prop given to each Timeout component in the ancestor path of the
thrown promise.
React should resume rendering regardless of whether it resolves
or rejects.
Async is not required for Suspense, but strict mode is.
Some of this was added with "soft expiration" in mind, but now with our revised
model for how soft expiration will work, this isn't necessary.

It would be nice to remove more of this, but I think the list itself is inherent
because we need a way to track the start times, for <Timeout ms={ms} />.
I think this separation makes sense, if for no other reason than it helps with
the mental model. A Timeout determines the threshold before a suspend "effect"
turns into an error. A Placeholder is like an error boundary that pattern
matches on those errors.
: 0xead1;
export const REACT_TIMEOUT_TYPE = hasSymbol
? Symbol.for('react.timeout')
: 0xead2;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These new symbols should be added to ReactIs and getComponentName.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably also need a follow-up PR for DevTools to add the new type in so it doesn't show as "unknown"?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also test renderer 😄

@pull-bot
Copy link

pull-bot commented May 1, 2018

React: size: 🔺+1.0%, gzip: 🔺+0.7%

ReactDOM: size: 🔺+1.1%, gzip: 🔺+1.2%

Details of bundled changes.

Comparing: ad7cd68...271aa2f

react

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
react.development.js +2.1% +3.1% 55.43 KB 56.61 KB 15.23 KB 15.69 KB UMD_DEV
react.production.min.js 🔺+1.0% 🔺+0.7% 6.96 KB 7.03 KB 2.96 KB 2.98 KB UMD_PROD
react.development.js +2.6% +3.9% 46.07 KB 47.25 KB 12.87 KB 13.37 KB NODE_DEV
react.production.min.js 🔺+1.2% 🔺+0.8% 5.5 KB 5.57 KB 2.4 KB 2.42 KB NODE_PROD
React-dev.js +2.7% +3.6% 46.07 KB 47.33 KB 12.55 KB 13.01 KB FB_WWW_DEV
React-prod.js 🔺+0.1% 🔺+1.7% 13.38 KB 13.39 KB 3.71 KB 3.77 KB FB_WWW_PROD

react-dom

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
react-dom.development.js +3.0% +2.6% 611.8 KB 630.2 KB 141.4 KB 145 KB UMD_DEV
react-dom.production.min.js 🔺+1.1% 🔺+1.2% 100.06 KB 101.14 KB 31.84 KB 32.23 KB UMD_PROD
react-dom.development.js +3.1% +2.7% 596.18 KB 614.57 KB 137.23 KB 140.92 KB NODE_DEV
react-dom.production.min.js 🔺+1.1% 🔺+1.0% 98.5 KB 99.55 KB 31.07 KB 31.37 KB NODE_PROD
react-dom-server.browser.development.js 0.0% 0.0% 101.34 KB 101.35 KB 26.45 KB 26.46 KB UMD_DEV
react-dom-server.browser.development.js 0.0% 0.0% 90.64 KB 90.65 KB 24.19 KB 24.2 KB NODE_DEV
react-dom-server.node.development.js 0.0% 0.0% 92.56 KB 92.57 KB 24.74 KB 24.74 KB NODE_DEV
ReactDOM-dev.js +3.1% +2.7% 620.62 KB 639.72 KB 139.99 KB 143.78 KB FB_WWW_DEV
ReactDOM-prod.js 🔺+4.4% 🔺+3.6% 284.19 KB 296.57 KB 51.94 KB 53.8 KB FB_WWW_PROD
ReactDOMServer-dev.js 0.0% +0.1% 94.11 KB 94.16 KB 24.03 KB 24.04 KB FB_WWW_DEV

react-art

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
react-art.development.js +4.4% +4.0% 414.71 KB 433.1 KB 90.31 KB 93.93 KB UMD_DEV
react-art.production.min.js 🔺+1.2% 🔺+1.2% 90.38 KB 91.44 KB 27.49 KB 27.83 KB UMD_PROD
react-art.development.js +5.4% +5.1% 340.55 KB 358.94 KB 71.63 KB 75.29 KB NODE_DEV
react-art.production.min.js 🔺+1.9% 🔺+2.1% 54.9 KB 55.95 KB 16.77 KB 17.13 KB NODE_PROD
ReactART-dev.js +5.5% +5.3% 348.81 KB 367.91 KB 71.21 KB 74.99 KB FB_WWW_DEV
ReactART-prod.js 🔺+7.4% 🔺+6.8% 166.92 KB 179.21 KB 27.43 KB 29.31 KB FB_WWW_PROD

react-test-renderer

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
react-test-renderer.development.js +5.3% +4.9% 348.62 KB 367 KB 73.37 KB 76.98 KB UMD_DEV
react-test-renderer.production.min.js 🔺+1.9% 🔺+1.8% 54.89 KB 55.95 KB 16.72 KB 17.01 KB UMD_PROD
react-test-renderer.development.js +5.4% +5.2% 339.45 KB 357.83 KB 70.66 KB 74.31 KB NODE_DEV
react-test-renderer.production.min.js 🔺+1.9% 🔺+2.1% 54.12 KB 55.17 KB 16.3 KB 16.64 KB NODE_PROD
ReactTestRenderer-dev.js +5.5% +5.4% 347.98 KB 367.07 KB 70.31 KB 74.07 KB FB_WWW_DEV

react-reconciler

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
react-reconciler.development.js +5.7% +5.5% 319.8 KB 338.19 KB 66.12 KB 69.77 KB NODE_DEV
react-reconciler.production.min.js 🔺+2.2% 🔺+2.6% 47 KB 48.05 KB 14.23 KB 14.6 KB NODE_PROD
react-reconciler-persistent.development.js +5.8% +5.5% 319.14 KB 337.51 KB 65.88 KB 69.53 KB NODE_DEV
react-reconciler-persistent.production.min.js 🔺+2.2% 🔺+2.0% 45.97 KB 47 KB 14.09 KB 14.37 KB NODE_PROD

react-native-renderer

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
ReactNativeRenderer-dev.js +4.1% +3.9% 459.6 KB 478.6 KB 98.34 KB 102.15 KB RN_FB_DEV
ReactNativeRenderer-prod.js 🔺+5.8% 🔺+5.4% 217.88 KB 230.45 KB 36.4 KB 38.35 KB RN_FB_PROD
ReactNativeRenderer-dev.js +4.1% +3.9% 459.35 KB 478.33 KB 98.28 KB 102.09 KB RN_OSS_DEV
ReactNativeRenderer-prod.js 🔺+2.0% 🔺+1.8% 217.09 KB 221.52 KB 36.27 KB 36.91 KB RN_OSS_PROD
ReactFabric-dev.js +4.3% +4.1% 442.01 KB 461 KB 93.94 KB 97.75 KB RN_FB_DEV
ReactFabric-prod.js 🔺+2.2% 🔺+1.9% 202.77 KB 207.14 KB 33.67 KB 34.31 KB RN_FB_PROD
ReactFabric-dev.js +4.3% +4.1% 442.05 KB 461.03 KB 93.95 KB 97.76 KB RN_OSS_DEV
ReactFabric-prod.js 🔺+2.2% 🔺+1.9% 202.81 KB 207.18 KB 33.69 KB 34.32 KB RN_OSS_PROD

Generated by 🚫 dangerJS

@sebmarkbage
Copy link
Collaborator

We've been able to do a lot of refactors and change significantly how React works because nobody relies on subtle differences in practice. The APIs we exposed are really the highest level possible that we could get away with, not the lowest level. The lowest level used to be updateComponent or something on the object oriented API and would be beginWork or something in the new API. Exposing the lowest primitive is on its own not a virtue.

What's the use case that can't be described with just a Timeout and do you expect people to actually use these separately in practice?

@acdlite
Copy link
Collaborator Author

acdlite commented May 3, 2018

I think there are many places where you'd use a Placeholder without a Timeout. In fact, I think usually you would use Placeholder without overriding the timeout.

There are no cases where it benefits you to use Timeout without a Placeholder. At least that I can think of.

So the reason to separate them is to avoid overuse of Timeout. I'm concerned if they're both in the same component, it'll be too tempting to specify a delayMs on every single placeholder. Which I guess isn't the worst thing in the world? Could lead to overcoupling but I suppose that's a factor either way.

Now that I type this out, a better solution might be to keep the two primitives combined but rename Timeout to Placeholder, like we do with the higher-level API we use in demos.

@sebmarkbage
Copy link
Collaborator

Yea, I think the only reason we named it Timeout was because we expected the higher-level thing to be called Placeholder and that you'd never use Timeout in practice.

Maybe that's just an indication that we do need the higher level thing to be built-in and we just have to solve the cross-renderer issue and what it means to hide something.

@acdlite acdlite closed this Aug 15, 2018
@NE-SmallTown
Copy link
Contributor

Should we link the pr(i.e. Just use PlaceHolder and deprecate Timeout) or add the reason why close this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants