Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

My issue with React is that it's truly hard. It markets itself as easy but it's not. I have 20 years of programming experience, I dealt with UI a lot, I used WinAPI, Java Swing, I know JS and HTML pretty well. I'm fine with reactive programming or async stuff. Yet I often struggle with React. I'm not a full-time web developer, I admit, I'm more like full-stack developer but when I need to write novel React code, I struggle a lot.

For example recently I wanted to use a promises in React app. I mean: promises are as native to JS as it gets. Surely React should have first-class support for promises.

Nope.

So I started to write custom hook. usePromise. Like useEffect, but for promises.

Well, it would not be hard. But apparently React likes to call useEffect twice for dev mode. So I need to have a reliable cancellation. How do we cancel stuff in web? With AbortController, right. Does React heard about AbortController? Nope. So I need to integrate AbortSignal within my usePromise hook. I read famous Dan Abramov article, I read other articles, I spent days tinkering around this thing, I wrote several implementations.

All of those implementations are faulty.

Here's my latest one: https://pastebin.com/WBctCBpc. Technically it works. But it contains unpure reducer function. It's not broken in current React version. But who knows how react dev mode will torture my reducer in the next version.

I have to admit that I enjoyed toying with this stuff. But it definitely counter-productive to business values.

Now I know that this is all solved and I should just use react-query or something similar. Well, I have my reasons to avoid it. But my point still holds: React is hard, React is not well integrated with JS and Web. And probably React will get better in the future. I've heard about suspension stuff which might just be what I need, but it's not there yet.



I feel more and more like React wants to be separate from JS and the web. Perhaps so that it can better fit React Native, I don't know. But it wants to be its own entire world and it's an exhausting thing to pick up at times.


I'm sorry but I don't share your experience. I find React very easy, and short of a period of creating the baseline components and skeleton, everything else flows very fast in terms of development time. By the way, I think react in strict mode does run components twice in dev, so not running in strict mode will prevent that, and you can use a regular Promise in your useEffect.


Strict mode is not something that should be avoided. In the future versions React will do stuff that it does with strict mode today. Of course you can use a regular async function in useEffect but you'll quickly notice that it's called twice in strict mode. And you'll want to abort running fetch. Then you'll notice that responses can arrive out of order and your state updated with outdated response which happened to arrive last. It's easy to use async code in useEffect. It's not easy to use it correctly.


Whether it should or should not be avoided is a preference. That is why it's not forced. I don't want or need it. And if I do, and it's caveated with double-useEffect - so be it. I have a feeling there is a lot of overkill in your approach but of course I lack context so apologies if I'm wrong.


The fact that “strict mode” means useEffect gets called twice feels like a great example of the ways in which React is not simple.

It’s not quite directly using a promise but I was surprised I can’t use an async function in useEffect. It’s pretty common to perform async operations there, after all.


useEffect IS a great (the best?) place to put async code. I do it all the time. The reason for strict mode rendering twice is to spot strictness related issues. Honestly I never even thought of using it so I've never experienced this.


What does usePromise is supposed to do?


It's supposed to run provided promise and return its status. If deps changed or component is unmounted while promise is pending, it should inform currently running promise using AbortSignal. And it should handle edge cases (e.g. promise is changed, second promise is started but first promise ignored abort signal and resolved to a value. This value should be ignored).

Basically it should remove any boilerplate from user of this API and handle edge cases.


Thanks. But what do you use it for? What promises do you want your components to be involved with and in what way?


For example HTTP request. Anything, actually. Some rough code:

    function Item({id}) {
      const r = usePromise(async (signal) => {
          const resp = await fetch(`/item/${id}`, {signal});
          return await resp.json();
      }, [id]);
      if (r.status == "pending") {
        return <div>Loading</div>;
      }
      if (r.status == "rejected") {
        return <div>Error: {r.reason}</div>;
      }
      return <div>{r.value}</div>;
    }
It's really like useEffect but provides better support for cancellation and properly tracks promise. Rewriting this snippet with useEffect correctly would require quite a lot of code (although rewriting this snippet with useEffect incorrectly is possible with not a lot of code, but you don't want to write incorrect code). Which has to be repeated everywhere.

Again, this task is better solved by react-query or its alternatives. What I'm writing is not strictly web-site, but rather a web-interface on embedded device and web-server is not remote web-server but thing that works on the same device, so for now I decided not to use those libraries which made for slightly different use-cases.


I think I'd go about it using redux-thunk because I feel like render function is not a great place for complex async state changes and chcecking internal status of a promise is a bit low level, but you've built a nice, easy to use thing. If you published it some people might find it to be exactly what they need. Plus they might help you debug some corner cases.


FYI, we recommend that most folks should not write promise management, data fetching, or loading status tracking code directly

If you're using just React, use React Query or something like `react-async`.

If you're using Redux, use the "RTK Query" data fetching and caching API in our official Redux Toolkit package:

- https://redux.js.org/usage/side-effects-approaches


Thanks, I'll think about it.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: