Back

Modern React, is a mess.

Clickbait title, I know. It's kinda true though.

Every 2 days, there's a new thing about react and how to use it, that the whole "it's just javascript" statement makes no sense to me anymore.

I've made a few statements about moving back to class components and, I've actually done that for a lot of components at work.

Another one of your futile rants?

Maybe, idk, I'm just a dumb guy.

A few months back I figured out that context shouldn't be used for state, and a few days after that, I read a post about it from library maintainers stating the same thing.

A little later I found an issue during maintenance of a project where a component was had excessive re-renders due to a dependency missing in one of the useEffect's and that was an easy fix, but then we figure out that we shouldn't be doing data fetches in useEffect altogether.

Source Tweet

Now the thread involves quite a few known people in the react community and I get the point of not doing it in useEffect but we were introduced to useEffect as an alternative to componentDidMount and if I wish to get data on mount I will put it in there.

I mean, we can use a data fetching library which also does this but then, we have to make sure that we don't update the fetched data into a state primitive due to internal react update paradigms. (also why micro state libraries are needed)

I could be wrong, I didn't write react, nor did I wish for it to be so complicated.

It doesn't end there though, there's been changes on how to do stuff in react quite a bit over the past few years and it feels like it's no more just a UI library.

It's got it's own way of doing things and this brings back the Angular environment where the community would just go crazy because something wasn't done the "Angular Way".

Now, react and react native are something I use on a daily basis and I can't just throw it up into the air since there's no other alternative to react native for me (I'm going to let flutter mature a little more before I jump on that train).

So, any solution after all this rant? Apparently not, The options include using libraries that handle these flows for you and falling into dependency hell and more of reading documentation than being able to write code and that's bearable, I guess.

Unless. Something breaks.

Then your options are to fork and fix and then you might do something wrong because "that's not how you do it react!"

Satire aside, the options really are to pick up good libraries to help you with most tasks and if possible stop using hooks altogether.

Why would I stop using hooks?

Based on posts and reading code bases / documentations, the primary reason for them to exist is to help library developers setup a good flow for you.

For example,

useSWR A library to fetch and cache keyed data or more formally an implementation of stale while re-validate which is a paper that specified the mechanics of returning stale data while revalidating for new data in the background.

The library is amazing and can handle most cases today because of the simple API that allows you to pass in a fetcher which is basically the function that'll define the data fetching logic.

Now, could you implement this yourself? Sure.

To simplify the behavior,

  1. A fetcher function that depends on a key
  2. The key is what decides what something will be cached under, like an identifier
  3. The hook is to return the error,data values and if there's neither then the network call is active or it's in loading state.

Simple right? Yeah, no...

The library isn't 500 lines for something that simple.

  1. It has to maintain a global state for you to be able to fetch the same stale data in other components that might also be in the view.
  2. You should be able to manage dependencies of each useSWR hook separately.
  3. The passed in fetcher needs to be cached so it's passed to a useRef and monitored.
  4. the key is also cached and monitored similarly.
  5. You need to see if it's the component's first mount and if the above 2 (key,fetcher) have changed since that first mount since a react component can have up to 4 renders on the "initial" component render.
  6. The error, data isn't a state(useState value) inside the custom hook but maintained in cache and fetched from it to be sent to you, because if it was just the state primitive swr would be causing a lot more renders on every mutate() call you trigger.
  7. There's also cases where you have to handle cancellation of these fetch calls since if the calls complete for an unmounted component then that's considered a data leak
  8. and this goes on (totally not trying to avoid explaining the remaining 100 lines)

So, can a frontend developer who's work was just to write a simple UI render after getting data from an API function or SDK do all this in every project?

But they only have to do it once and then copy it everywhere!

Yeah and then copy the fixes back to the older projects, right?

Don't claim it to be beginner friendly when it's not, and it's definitely no more javascript.

All that bashing to promote your library?

Nah, my library doesn't even solve all the above problems, and it probably has more issues that I can even imagine right now and I'll only find out about them as it starts getting used by more and more people.

So, no.

My libraries have nothing to do with this. Also, I haven't even mentioned any of them in the post yet.

But it works!

It does, and it works beautifully. I've mentioned it before, I don't hate the library, but that doesn't mean I'm not irritated by the decisions.

Luckily I'm not smart enough to sit and write my own UI library that'd work everywhere (web,ios,mac,windows) so, I'm going to have to adjust to the decisions taken by the devs of react but, I can sure put it out there that something is wrong.

The devs of react will have convincing reasons for those decisions and I might have missed them while going through the RFC's , so that's wrong on my part.

Just use class components then!

Ah yeah, about that. I already am.

Sadly, the amount of HOC's I have to write to get the data from libraries that only have hooks is rather high but that's okay, that's still a manageable way to do things (at least, right now)

The only magic point in class components was the this.setState call and everything else was just simple plain javascript, I could control what would cause renders with componentDidUpdate and componentWillReceiveProps and honestly that control is missing so yes, class components is a good option. ( Yeah, React.memo exists but the docs ask you to refrain from depending on it)

So, valid options are

  1. Class Components + HOC's to get data/actions from hooks
  2. Good libraries that you can trust the devs are actively maintaining (so, nothing from my github!)

Finally,here's resources on things that'll help you be a better react developer in case you wish to know the right way to do things

Oh also, on the contrary the react docs do ask you to make ajax / api calls on useEffect.

  1. https://reactjs.org/docs/faq-ajax.html#example-using-ajax-results-to-set-local-state
  2. https://tkdodo.eu/blog/avoiding-use-effect-with-callback-refs
  3. https://tkdodo.eu/blog/use-state-for-one-time-initializations
  4. https://kentcdodds.com/blog/how-to-use-react-context-effectively
  5. https://kentcdodds.com/blog/application-state-management-with-react
  6. https://www.joshwcomeau.com/react/why-react-re-renders/

You can find more by yourself, but hopefully this has been a nice rant for you to read.

Adios!

Update: Added another link (6.) above as it does explain quite a bit visually