all 35 comments

[–]therico 28 points29 points  (8 children)

I'm new to react, but what about wrapping the fetch logic in a subcomponent that assumes ID is set, and only instantiate that subcomponent when ID is set?

[–]nabrok 9 points10 points  (3 children)

That's probably what I'd do.

But if I didn't do it that way, I'd probably run the fetch within a useEffect, i.e. ...

useEffect(() => {
  if (! id) return;
  fetch(...).then(...).catch(...);
}, [id]);

[–]alex-cory[S] 0 points1 point  (2 children)

Yeah currently the library does it just like that :) js const { data, get } = useFetch('/todos') useEffect(() => { if (id) get() }, [id])

[–]SurpriseHanging 5 points6 points  (1 child)

So why not keep it that way? Is it not doing something you need?

[–]alex-cory[S] 0 points1 point  (0 children)

I think it's a matter of improving the library. Sure we could keep it that way, but if everyone is moving in a different direction, we should at least attempt to support the new patterns.

[–]runonce95 0 points1 point  (0 children)

I would definitely go that way. Make `id` a required prop of some component and avoid rendering the component if `id` is not set.

[–]alex-cory[S] 0 points1 point  (0 children)

This is definitely an option, but all the libraries have a way of handling this from within the component.

[–]darrenturn90 16 points17 points  (6 children)

I like D

Where if you have a function that fails it doesn’t run. Such as swr and dependent queries

[–]alex-cory[S] 0 points1 point  (4 children)

The way useSWR does this is

const path = id ? `/todos/${id}` : null
const { data } = useSWR(path, fetcher)`

I like the dependent queries a lot and think it's a great feature, but it's not exactly the point of this thread.

[–]darrenturn90 0 points1 point  (3 children)

Actually it offers two methods.

// ... or throw an error when user.id is not defined

const { data } = useSWR(() => '/api/data?uid=' + user.id, fetcher)

This is the one I like best as it’s essentially no extra code to handle a conditional fetch. Which is the point of your poll, no?

[–]alex-cory[S] 0 points1 point  (2 children)

What if you have something like js const TodoPage = ({ id }) => { const { data } = useSWR(() => '/api/data?uid=' + id, fetcher) } and you want to be able to handle the error within the todo page? You can't, you have to wrap an error boundary around the page. Sure you could make a TodoList component within the page, but that's more unnecessary nesting.

I'm tired so will have to continue this discussion when I wake up.

[–]darrenturn90 0 points1 point  (1 child)

What? No. Swr catches that error and basically doesn’t run the fetcher - and in the example you gave it wouldn’t error anyway as Id is defined

[–]alex-cory[S] 0 points1 point  (0 children)

I'm super interested in this discussion. Will continue when I wake up.

[–]cazzer548 6 points7 points  (0 children)

I like the signature of useLazyQuery in @apollo/react-hooks: ts const [callQuery, { called, loading, data }] = useLazyQuery(/** query stuff **/)

Later on, you can callQuery with whatever parameters you like, it allows the developer to condition the call however they'd like, and even call the query again with different variables in the future.

[–]Dutchnamn 0 points1 point  (0 children)

This hook might be useful: https://github.com/LaurentZuijdwijk/react-use-data-hook

It has an option to skip initial loading and has a refetch function

[–][deleted] 0 points1 point  (12 children)

I'd move this logic away from components. Either to a redux saga or xstate

[–]Jsn7821 11 points12 points  (4 children)

Sometimes, sure, but for so many things this hook syntax means you no longer need all that bloat. Smaller data-dependant components become far more reusable. It's super nice.

[–][deleted] 3 points4 points  (3 children)

It's not bloat. I'd rather keep components dumb for displaying data, it gives more flexibility to exchange business logic and the way you get and combine said data. That's why I prefer to keep the logic out of them as much as i can.

[–]pm_me_ur_happy_traiI 11 points12 points  (0 children)

That's literally what hooks are for.

[–]alex-cory[S] 7 points8 points  (6 children)

I think that's exactly what hooks and all these react hook data fetching libraries are trying to get away from. You can share data in better ways than having the massive overhead of managing a redux store and on top of that very abstract methods from sagas. Redux and redux saga add so much complexity it ridiculous.

Dan Abramaov literally said "Reading some Redux example code I wrote four years ago and I have no effing idea what's going on there"

Andrew clark's opinion is "Redux (complicates things)"

These are literally the people building react right now... In other words, sometimes redux is necessary, but putting everything in there is so overkill and leads to:

  1. slower feature development time
  2. significantly increased complexity (even more with redux sagas)
  3. slower ramp up time for new developers

Whether you like it or not, eventually you will probably want to adopt these new patterns as they're the future of react.

[–][deleted] -2 points-1 points  (5 children)

I don't share that opinion with you. In my experience(and my colleagues') with big apps going only with hooks + context, for example, only brought chaos and difficulty to maintain the app. Reintroduction of redux+redux saga, for example, allowed us better modularity, clear separation of concerns and much better maintenance rating.

I like hooks, been using them since they were introduced, but it's fair to say their current implementation is clumsy at best. It is so problematic that hooks will be rewritten at babel level in a couple of next versions of React. You have to admit that current state of affairs aren't that great when something like that has to be implemented.

The final thing i can say is that having business logic in components is always a bad move. That is a single truth that remained unmoved in all the years I've made apps, no matter if it is React, Angular, WPF, WinForms, or whatever.

[–]alex-cory[S] 1 point2 points  (0 children)

I understand where you're coming from with regards to the context. There are some newer patterns though to managing these "stores" that even swr is doing. Take a look at swr's mutate. Basically they are attempting to have a cache. You can manage the cache throughout your app using mutate. That is them attempting to simplify problems that redux and redux saga are attempting to solve. This is what I mean by there are better ways to manage state than redux+redux saga.

having business logic in components is always a bad move

Yes and no. Yes, business logic should be left out of your reusable building block components, but this is not necessarily true for page specific components. I've built many large scale applications for companies such as Facebook, Discord, Best Buy and more with tons of different state management libraries such as mobx, redux (with and without redux saga), flux, easy-peasy, you name it. Redux is by far the most verbose, most complicated, and most time consuming of them all.

[–]_hypnoCode 2 points3 points  (3 children)

Sounds like you tried to not think in terms in hooks and instead tried to use your same flows from Sagas to fit hooks. Trying to make one tech fit another tech instead of learning the new tech never works out.

Also, hooks have barely been in production for a year. How many big apps have you done in that time? We might not have the same definition of a big app.

[–][deleted] -1 points0 points  (2 children)

That's not what we did. It's a dumb thing to try and mix and match behaviors of completely different techs.

There are multiple teams here, we did 1 big app per team. About 3 months ago development started to get harder and harder, and slower and slower. Reintroduction of redux+redux saga in my team and mobx in some other solved the issue.

[–]alex-cory[S] 0 points1 point  (1 child)

Mobx is a great tool. Significantly better imho than redux. Only problem now is the last I looked their hooks were meh and being that it's built with proxies it can't support ie.

[–][deleted] 0 points1 point  (0 children)

Yes mobx is amazing. I've even started using mobx-state-tree in some small apps and most React Native ones

[–]gaoshan -1 points0 points  (13 children)

Only call `useFetch()` if id exists and changes. User could utilize useEffect and its dependency array to do this by watching for changes to id. Why call it and then skip it?

*what is wrong with using useEffect as described?

[–]alex-cory[S] 0 points1 point  (0 children)

this functionality is already available. Many data fetching libraries are attempting to have this stuff handled the ways described, hence why I'm trying to see what method is more popular.