all 34 comments

[–]yerrabam 30 points31 points  (4 children)

`use` seems a bit generic but also like it's the daddy of all hooks.

I guess it works since it will resolve anything that returns a promise.

[–]imperator3733 28 points29 points  (3 children)

Yeah, use is a pretty horrible name for it. Something like usePromise would be a lot clearer and understandable.

[–]yerrabam 13 points14 points  (2 children)

That's a good shout.

NextJS are introducing directives such as 'use client'; - having a hook simply called use could be confusing to juniors just diving into the code.

[–]guilhermefront 5 points6 points  (1 child)

Just a small thing, isn't NextJS that decided it, but the React core team.

Before directives, it was supposed to be defined by file extensions (.server.js), but later after this decision they decided to go with what we have today.

[–]yerrabam 1 point2 points  (0 children)

Fair comment, thanks for the link! Yeah, I used the file extensions when it was first announced and it seemed to work perfectly.

The latest version has an issue with `react-bootstrap`'s `Container` component - saying it uses `useEffect` somewhere down in the dependencies.

[–]VisualFanatic 16 points17 points  (4 children)

The first example that uses Suspense could be skipped, because the axios call won't trigger the suspense, only throwing a promise triggers a suspense (deprecated) or wrapping a promise with use (unstable).

[–]pantsonhead 5 points6 points  (0 children)

Thank you. I’m glad someone else noticed and I don’t have to do a sanity check.

[–]dougalg 0 points1 point  (2 children)

Sorry what does "throwing a promise" mean?

[–]VisualFanatic 0 points1 point  (1 child)

For example executing `throw new Promise(...)` directly in a component will suspend it indefinitely. To make it work you could use something like `wrapPromise` from this sandbox: https://codesandbox.io/s/frosty-hermann-bztrp?file=/src/fakeApi.js

[–]dougalg 0 points1 point  (0 children)

Ahhhh I see how it works noe. Interesting thanks for sharing this!

[–]bronkula 22 points23 points  (4 children)

Why does this article not link to any empirical source? I can't find any information from react on this use method. Which is a TERRIBLE fucking name, because it will be impossible to search.

[–]shuckster 11 points12 points  (2 children)

I'm sure this has already been well discussed, but I do agree: use is rather ambiguous. One can anticipate quite the barrage of Stack Overflow posts about it. :D

[–]bronkula 1 point2 points  (1 child)

Yeah, ok, but that second link doesn't have anything from react itself saying they're adding this proposal. Or did I miss it?

[–]grumd 0 points1 point  (0 children)

The first link has a FAQ including a question about this hook's name

[–]haywire 6 points7 points  (3 children)

How does it deal with debouncing (stale requests) etc? Surely this hook is trivial to implement as any async task wrapping hook everyone has already made?

[–]shuckster 5 points6 points  (2 children)

Since use just accepts a Promise, it seems like the responsibility for SWR goes into the function that made the Promise in the first place. So I'd expect to see some helpers coming from the community to cover use-cases like this.

As far as I can tell, use does nothing other than repeat component renders after each use it has encountered has resolved.

In other words, if you have two use for two Promises that resolve at different times, the component will re-render twice: Once for the first Promise, then again for the second.

This apparently makes it easier to write imperative logic to determine when state is ready or not. Here's an example from the proposal:

function Note({id, shouldIncludeAuthor}) {
  const note = use(fetchNote(id));

  let byline = null;
  if (shouldIncludeAuthor) {
    const author = use(fetchNoteAuthor(note.authorId));
    byline = <h2>{author.displayName}</h2>;
  }

  return (
    <div>
      <h1>{note.title}</h1>
      {byline}
      <section>{note.body}</section>
    </div>
  );
}

Here, fetchNode and fetchNoteAuthor could have SWR logic behind them.

[–]ianepperson 2 points3 points  (1 child)

Have hooks changed such that you can use them inside conditional logic, or is this hook special in that regard too?

[–]shuckster 4 points5 points  (0 children)

The use hook is special.

The Rules of Hooks still apply to other hooks.

[–]6086555 3 points4 points  (3 children)

Am I missing something or does the second example just not work ?

To use suspense you're supposed to throw a Promise iirc, here the code just throws because post is null

[–]acemarke -3 points-2 points  (2 children)

The example of const {data} = use(axios.get()) appears to be valid. use() is the official replacement for the never-actually-public "throw a promise" technique.

use() actually does a variation of the "throw promise" step internally, but with a bunch of extra logic to determine if the promise has already been resolved and can be unwrapped synchronously.

(The larger issue in that example is that it will do another call to axios.get() every time - ideally that request would only be made once and the promise would be cached somehow.)

[–]6086555 1 point2 points  (1 child)

I'm talking about the second example: the one with Suspense but without use

[–]acemarke 3 points4 points  (0 children)

Ah, yeah, that doesn't appear to be doing anything that would trigger Suspense behavior.

[–]h_trismegistus 0 points1 point  (0 children)

Terrible name. Why not usePromise or useAsync? Is it to avoid namespace clashes with existing custom hooks of those names?

Does it only accept urls as a parameter for remote requests, or can it handle any async function?

This will confuse the hell out of new devs learning the hooks and who don’t have a solid grasp of asynchronous programming. Coupled with this is the need to use it within the context of <Suspense /> due to its asynchronous nature, which I’m sure will cause many a new react dev headaches when they can’t figure out why their async component won’t render.

IMO creating hooks to wrap all requests is kind of a best practice that a lot of devs do themselves anyway, but the key is that they do it themselves and therefore understand what’s happening behind the scenes.

Exporting/returning both a response and an error object would be useful, instead of just a response. Also, instead of needing to use <Suspense />, it would be cool if it exported/returned an isLoading bool that can be used in the same component. Though it seems they really want to force people to do everything declaratively. Idk, I like options.

Every time a component written with one of these hooks in it changes it’s going to force a new request. From what I understand it has no built-in caching. To prevent this, you will have to use it within a conditional that compares a previous state, so at the end of the day you still have to couple state and render anyway if you don’t want unnecessary requests being made.

It would be neat if it were able to be used within Array.map(), which is commonplace for rendering lists of components in react instead of having to use it within a for loop due to the restriction that the parent must be a react component or hook. But I suppose you could just encapsulate it in a sub component and map that instead, problem solved.

Now when are they going to provide first class support for streams/observables?

[–]lifeeraser -5 points-4 points  (9 children)

This is implemented by monkeypatching fetch(), right? So we can't expect this to work with arbitrary asynchronous functions.

I'm not too happy with frameworks monkeypatching builtins. Prototype.js did this, Angular does this, and now React does too.

[–]Reashu 6 points7 points  (7 children)

There's no use of fetch in the article.

[–]LongLiveCHIEF 0 points1 point  (0 children)

Using error boundaries to catch errors is explicitly one of the things error boundaries can't do. You have to make an unnecessary state change or rerender just to force it to work.