reactjs / rfcs

RFCs for changes to React

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Promise children

subhero24 opened this issue · comments

I could not find a discussion on the following anywhere. I hope this is the right place for asking such a question.

When using a promise as a child, react currently throws Objects are not valid as a React child (found: [object Promise]). If you meant to render a collection of children, use an array instead.

function Component() {
  let promise = new Promise((resolve, reject) => {
    setTimeout(() => { resolve('text') }, 1000)
  })

  return <div>{promise}</div>
}

Would suspending the component when the promise is pending, and resuming / rerender the promise value when resolved be possible? Suspending the component manually when the promise is not yet resolved, prevents the component from returning a react element, and thus prevents the component from already rendering concurrently.

Are there any issues (performance or otherwise) with dealing with promises as a child in react elements? I assume there are, but would like a little more insight. What would the issues or trade-offs be implementing this?

The identity of the promise would not be the same between renders, since the promise is being created within the render.

So even if React waited for the promise to resolve and attempted to re-render, it would immediately fail again since there's a new, not-yet-resolved promise in the children components.

It's necessary to use useEffect to make this function correctly (see the recent fetch-on-render tutorial in the suspense documentation).

It's impossible by design to "leak" such a promise value outside of the useEffect callback since the callback runs after rendering occurs, so there's no way to actually accomplish what you're trying in a consistent way.

Thanks for your explanation. I was wrong to include the promise in my render function. I meant to use a cached promise, as stated in the docs about suspense. I meant to do something like this:

let promise = new Promise((resolve, reject) => {
  setTimeout(() => { resolve("text") }, 2000);
});

function Component() {
  return (
    <div>
      {promise}
      <OtherComponent />
    </div>
  );
}

If react could suspend the component after encountering a not resolved promise child, I would not have to suspend from Component myself. Doing the suspending myself from Component, prevents OtherComponent to start rendering concurrently. So I would have to create some AwaitPromise component, pass the promise as a prop, and suspending from within AwaitPromise if the promise was not yet resolved. This is a lot of (unnecessary?) glue code that I would rather not write.

I hope this explained my thoughts more clearly than my previous post.

commented

Hi, thanks for your suggestion. RFCs should be submitted as pull requests, not issues. I will close this issue but feel free to resubmit in the PR format.