How I write React after 8 years
nesbtesh.medium.com
nesbtesh.medium.com
No. You can do that with a global variable. Redux’s main features are serializable actions, serializable state, plus localized updates if you use immutable data. It gives you the ability to throw your state at localstorage, send actions over a websocket, easily traverse history (undo, time travel) and keep a log of changes. It’s ok to not need any of this, most projects don’t, but at least write off the library for the correct reasons.
> React is fast by default
Also not true. React does basically no optimization at all besides batching state updates. Your computer is just fast enough that you’ll think it doesn’t matter until it’s too late. Optimizing rendering is 100% on the application author.
Incidentally, I have to agree with the author directionally on this point. Redux makes codebases such a pain in the ass to work with. Every new change you want to make to the store, you have to make about five changes across five different files. When you're working on a new feature you spend most of your time just wrestling with Redux, creating an action type, creating an action creator, creating a reducer, importing/exporting all this shit, blah blah blah. Then a new engineer who wants to figure out what the code is actually doing has to trace through the action, then the action creator, then the reducer, blah blah. This is before you throw in stuff like epics and run API calls through your action/reducer pipeline. It is no wonder productivity per capita in tech is so low.
This has never actually been a requirement to use Redux. Admittedly, having separate folders and files by type _was_ a pattern that was shown in the docs originally ( `reducers/todos.js`, `actions/todos.js`, `constants/todos.js`, etc), but even in the early days the "Ducks" pattern of "put all the logic for a feature in one file" was a thing that you could do.
Today, we specifically teach "slice/ducks files" as the standard approach [0] [1], and Redux Toolkit's `createSlice` API makes it trivial to do that - just write the reducers, export the matching auto-generated action creators, and you're done.
> throw in stuff like epics
We've actually been advising _against_ using both sagas and epics for side effects for years now, and especially against using them for basic data fetching.
Today, Redux Toolkit's "RTK Query" data fetching and caching API is a complete solution for caching server state on the client, and we also recently shipped a new "listener" middleware that is a simpler alternative to sagas and epics for other reactive side effects.
[0] https://redux.js.org/tutorials/essentials/part-2-app-structu...
[1] https://redux.js.org/style-guide/#structure-files-as-feature...
I guess some people see the enshrined procedure as a feature and not a bug, and it is possible you could weigh the benefits of Redux's features against the cost in engineering time and decide it's worth it.. but it doesn't seem like this tradeoff is being consciously made and analyzed. It seems more like everyone just assumes they need something like Redux the moment they have global state.
There is too much know-it-all-ism in dev.
- Use the React DevTools Profiler to identify components that are rendering more than expected, or taking too long to render
- Wrap key components in `React.memo()` to have React avoid recursing through those subtrees unless the component props have actually changed
- Avoid putting large state objects into a single context provider, as all components reading that context will re-render whenever it changes (and all of their children too)
- Use `useMemo` to cache any expensive transformations that happen during rendering
I've got an extensive post that covers how rendering works as a whole, and has a section on understanding React perf optimizations:
- https://blog.isquaredsoftware.com/2020/05/blogged-answers-a-...
I'd rather write 5 lines of code using a library that I might have to replace later than write 100 line of code to future proof my function from the start.
I think there is a lot of merit to not using libraries. It might be a bit too strong to have a principle to never use libraries, but there are many libraries that provide way more than most projects need.
Also, who cares about future proofing for some unknow future. Write what solved the problem and then if another problem arises in the future - solve it then.
For example, the migration guide for react-query: https://tanstack.com/query/v4/docs/guides/migrating-to-react...
The only opinion I'll give is that if you think there's a right way to do anything all of the time, your opinion is probably wrong.
Every project is different. Just on the to use / not to use libraries bit, most of the time you probably want to optimise for fewer lines of code (assuming you can find a decent library that does what you want). However, sometimes if you're writing frontend code you'll want to optimise for other things like bundle size, browser support or performance. In which case you might actually want to write something in 50 lines, instead of a library import + 10 lines, because that import might add 200kbs to your bundle or not support IE properly.
A good developer is one that understands these trade-offs and considers them in the context of the project's objectives. Hell, sometimes it's not even about the project, but just developer preference. There have been times I've done things in ways I don't like simply because I know it's the way the most of my team prefer.
That's a good one. The next time I run into my competitors at a trade show, I'll be sure to recommend they do this.
Just, I certainly agree in this point, just leave the management of leap years to the date data type of the platform. Don't ever, not for a second (leap or not), think that += 24*60*60*1000 could be acceptable. But chances are you'd be far more aware of that wrongness while throwing together some novel date picker than anywhere else you might be tempted, where usually the peculiarities of calendar are far out of scope.
Native date pickers are limited in how you can style and customize them. As a dev, I'd always prefer a native one, but if design wants a unified look across platforms or any unusual behaviors, bespoke might be your only option.
Writing your own datepicker is 99% of the times a rookie mistake.
If I‘m hiring a front-end developer I‘m sure as hell not paying them to write custom datepickers all day.
Development is full of compromises.
And what do you think their job title and experience are?
> If I‘m hiring a front-end developer I‘m sure as hell not paying them to write custom datepickers all day.
This is the opposite of what you said above.
Should every frontend developer be reinventing date pickers from scratch just to demonstrate how good they are? I don't think so.
That's why I said 99%. Maybe there's an 1% or even less where it makes sense to reinvent it because you're Airbnb or Amazon or Google or you are in the date pickers business.
But yes, you are still a frontend developer if you don't do your own datepicker and focus on shipping your company product. And date pickers are built by frontend developers. What's your point?
Advice like not using libraries will have very polarized reactions (as evidenced by this thread) based on what kind of goals people are working on. Some react projects are very short lived so common problems like a library no longer being maintained are a non-factor. For large scale projects, typing loc is not a bottle neck, changing a foundational library that everything is based on is a potential massive timebomb.
And then there's all the decisions (like a date picker) where it can go either way.
I prefer having to keep up to date with libraries than having to deal with tons of some "smart ass" reinvention of the wheel that doesn't have documentation and tests and it's full of bugs and corner cases.
The code you write yourself also requires maintenance.
const [count, setCount] = useState(0);
And that's after the import and wrapping in a function (sorry, "hook"). For a variable. A single variable. Every. Single. "Reactive" variable. To which there's also rxJS and its observables.
Can you build bigger things more cleanly than with vanilla JS? Arguably, yes. I came up when the web was new, before JQuery and Prototype. I remember the chaos. I'm not saying we should go back. Again, React and the others were created for very good reasons.
let count = 0;
That's what I want: to bind that to a tag and walk away. For that, you need a compiler. Not the JSX nonsense and TypeScript transpilation, a real compiler. Like Svelte. I honestly don't care if Svelte specifically "wins", but that model needs to prevail. Otherwise we'll just keep building on sand and wondering why the code turns to crap every two years as new folks are added to the team and old ones leave after the React team decides functions are better than classes after all.
- Don’t use (almost) any libraries
- Redux is scrap - These days I use hooks and a tiny store with Immer, but I carry the golden lesson from Redux about one-directional data flow and UI as (mostly pure) function of state
- Centralizing API calls in one place
- Decoupling logic from components
- Any component that expects a state has a hook
- Components with index.js and index.scss
Less agree:
- CSS: Use styled components - I prefer Sass, CSS modules, Tailwind (gradually moving to latter)
- Route-based folder structure - Yes but more feature-based structure
- Native like Page Transition - Meh, not worth it unless done really well to improve UX
- Context - Never needed it
You've just reinvented Redux, except worse in every way. Just use Redux toolkit.
This is a fundamental react principal as well. It's how I wouod explain react to a newbie.
Button.tsx Button.spec.tx Button.css
Proceeds to recommend several libraries.
Unfortunately the opinions in this post are an odd mix of correct, incorrect, or irrelevant.
If only they focus on React and included a default vetted router, Meteor would probably still be thriving today. Instead they tried to please everybody and ended up satisfying nobody.
MDG ultimately pivoted to Apollo and _that_ stuck like glue everywhere, so I am happy they ultimately found success.
I still miss Meteor though, it was so stupidly productive early on.
So, the Meteor magic was just not thinking about await?
Don't use 3rd party libraries: NIH syndrome is plaguing our industry like a disease already. Can't wait until companies realize they need half the devs they do now. Our industry needs a wake up call, especially for immature developers who waste company money
Forms don’t have to suck: Just use hook form, or use uncontrolled forms. Or better yet if you have a simple form don't use a frontend library at all.
Any component that expects a state has a hook: Please God no. Write code. When you write it 3 times abstract it.
CSS: Use styled components: No
Components: No, use flat file structure. Don't use the whole Folder/index mess. It's a nightmare. Just do Button.tsx, UserFeed.txt / etc. Put components next to feature unless they're generic. Just use tailwind.
Split the routes using loadable components or the equivalent in Next: Ok.
Folder Structures: No
Decoupling logic from components: 100% never do this. Ever.
Native like Page Transition: No. Don't use animations for page transitions on web or PWA's. Those are reserved for actual native apps.
Context’s: Don't use Context, unless it's literally for if the user is logged in. Everything else should use some kind of 3rd party library (Mobx, Redux, Recoil, Zustand) that uses subscriptions to circumvent React's extremely slow and outdated way of rendering. Alternative: Use react-query for most date fetching / global state.
> Decoupling logic from components: 100% never do this. Ever.
Care to elaborate? I much prefer to decouple my business logic from my components - mixing logic with the view layer doesn't seem like a great idea, at least ime.
I've also had a good experience with a single folder containing all the relevant code for a component (types, style, test, etc).
Most rendering is outside the scope of state management and it doesn't matter whether you use providers or redux to manage it.
Personally I find the hooks for context a MILLION times easier to work with than redux was. Redux has introduced a lot of unnecessary complexity to several apps I've worked with. There was a time when it was the best choice but no longer, in my opinion.
> Decoupling logic from components: 100% never do this. Ever.
Disagree. "Dumb" components are often ideal and work great with testing libraries.
- https://redux.js.org/introduction/why-rtk-is-redux-today
- https://redux.js.org/tutorials/essentials/part-2-app-structu...
- https://blog.isquaredsoftware.com/2022/06/presentations-mode...
If other options do work better for you, great! I've just seen that many people's opinions of Redux are based on outdated info that doesn't match how "modern Redux" looks and is used today.
Redux _was_ overused in the first couple years. The original patterns _were_ very boilerplate-y. There _are_ a lot of other good tools for varying use cases that overlap with things that people have used Redux for: Context for prop drilling, React Query / Apollo for data fetching, Zustand/Jotai/Mobx/five-million-other-libs for state management.
Redux will never be the "must use this" lib again the way it was there for a couple years.
And that's a _good_ thing, because folks should take time to think about what problems they actually need to solve in their apps and pick the tools that work best for those problems.
But it's also true that Redux _is_ still a useful tool, and that RTK has addressed the pain points in using Redux. So, still very much a viable choice today, and the positive feedback we get on RTK daily shows that.
Really, the bigger issue today is that a lot of folks don't seem to understand the technical differences, tradeoffs, and intended use cases between a lot of these tools.
I wrote an extensive post describing the differences between Context and Redux to try to help with that:
- https://blog.isquaredsoftware.com/2021/01/context-redux-diff...
I've also been trying to start up a community-driven site to list common tools for various use cases (state management, styling, build tools, data fetching, etc), to act as a resource to help clarify this sort of confusion:
- https://github.com/markerikson/react-community-tools-practic...
Sadly I haven't had time to push it forward myself due to all the other responsibilities and tasks on my todo list, but hopefully at some point we can get enough info filled in for it to be a real resources that we can point people to.
Cursory glance indicates some of this is convenience wrapping of some normal react patterns instead of a refactor of redux. Is that fair?
- store setup: `configureStore` creates a store with a good default config in one function call
- Reducers: `createSlice` lets you define case reducers as functions in an object, write "mutating" syntax for immutable updates with Immer, and auto-generates the action creators for each reducer
- Data fetching: `createAsyncThunk` abstracts the standard "dispatch actions before and after an async request" pattern
- RTK Query: completely abstracts the _entire_ data fetching and caching process, adds cache entry lifecycles, auto-generates React hooks for use in components
The only React-related bits in RTK are the auto-generated React hooks for RTK Query endpoints. Everything else is "here's all the same kinds of logic you've always written for Redux, but with 1/4 the code and good default behaviors".
See https://redux.js.org/tutorials/fundamentals/part-8-modern-re... and https://blog.isquaredsoftware.com/2022/06/presentations-mode... for overviews of what changes from legacy "hand-written" Redux to RTK and how to use the RTK APIs.
It does matter - a Context at the top of your app will trigger a full re-render on every change. Redux and other state management solutions specifically avoid using Context, and the new React 18 useSyncExternalStore hook was added for this very reason.
Further, the entire point of global state is you only put the stuff in there that might actually require child components get re rendered. If you're shoving everything into global state or using context when you don't need it you're doing a lot of things wrong and it's likely you'd abuse redux as well.
Global state is the road to insanity in ant react app. Prefer props in all cases.
Lol, they are not reserved for actual native apps. Web can do animations just fine, at 60 fps, in 2D or 3D. If it adds to the user experience in a meaningful or delightful way, go ham.
I'm sure you have your reasons for your opinions, but you didn't define them, you just said "no this, trust me" essentially.
You did expand on usage of the Context API but I agree with your opinion already on that one.
FWIW, the stance of both the Redux maintainers (myself and Lenz) and the React/TanStack Query maintainers (Tanner and Dominik) is:
- If you're using Redux at all, prefer using RTK Query
- If you're using just plain React, prefer using React Query
but don't write data fetching and caching logic by hand :)
There _are_ some API and philosophy differences between RQ and RTKQ. RTKQ emphasizes defining "endpoints" up front, and generates React hooks based on those endpoint definitions. That approach also helps enable codegen from OpenAPI and GraphQL schemas. RTKQ also has some unique capabilities around cache lifecycles that enable use cases like streaming updates:
- https://redux-toolkit.js.org/rtk-query/comparison#unique-cap...
(I'll also note that we have an `<ApiProvider>` that automatically sets up a Redux store for you internally, so you _can_ use RTKQ if you're not already using Redux in an app.)
I will not hire someone who holds this view, straight up. It's the only technical belief (aside from crazy things like don't care about quality) I can think of that would instantly disqualify a candidate in my mind. Everything else feels negotiable and perspective-relevant, but not this.
It's such a massive waste of time to try and rewrite functionality that already exists elsewhere, and an inability to trust other people is a huge, bright red flag when it comes to working with others on the team.
Being very selective of which libraries you use? Sure, fair. We can talk about various lines and where to draw them, but categorically denying library use? That's unacceptable.
For folks who don’t agree wholeheartedly, I’d highly recommend spending the time to read through libraries you’d instinctively reject. It’s incredibly eye opening. The stuff you’d reject anyway is almost always easy to spot. The stuff you’d make an exception for is almost always an educational experience about the complexities of what the particular library solves, and may give you insight into its domain or a very sound warning you don’t have or want to wander into its domain.
One of the problems you are facing is code quality, which you've eloquently solved by code review (LOL), but the other, more burning matter is, you are no longer in control of your own software.
-- hey now, I DID actually read all the code we brought in
I mean, sure, that's a possibility. I don't believe you, but that's besides the point.
The point, being, and here's a news flash for you corporate peps out there who love to "manage my team of peps using stuff I learned from someone I talked to at a bar"...
Nothing is free in this world, not even code. The shortcuts you are making aren't really shortcuts. Instead, they will become your doom.
In all seriousness I get your point, code supply chains are volatile beasts that can blow up, but it's the only realistic way to write code nowadays. You can reduce external libraries and tools as a tradeoff for time/cost or you can fork tools to host yourself, etc... These are all tradeoffs that shouldn't be seen in black and white!
That's repulsive.
You could hold that position, if you wanted to, because the world seems that way, doesn't it? But i don't believe even for a fraction of a second, that you are right to say so.
> We're discussing React in this thread, are we not?
So, by this, what you mean is purely limited to React? Or FE code? Or code in general?
I was actually talking about code in general but then I threw the wrong card at you, because you had me cornered and I panicked. Please accept my apologies.
But I'm still in the right and you're still in the wrong. Because what you are saying is "my disciples, go into the night and depend on whatever you may, because depending on things is the way, for I will be rich if you do."
'Tis not the way. Is all I'm sayeth.
If this just means being selective about dependencies, I'm sure most of us here will agree.
Rejecting useful libraries because you "are not in control" means you're constantly reinventing the wheel, which means you're wasting time.
My boss doesn't care whether I use third party libs or my own code, and I bet yours doesn't either. They care about results. You simply cannot deliver if you write every piece of your stack from scratch.
In a business setting you have no control over what will happen with your software in the long run, and somebody else will take over for you, so this is an INCREDIBLY weak justification for not using libraries.
One of the major appeals of libraries is that the very fact you can figure out how to use them means that somebody else can. That’s something you can’t say about your own code as easily. If you don’t reuse other peoples code, how can you know the first thing about writing code other people can reuse? Not using other peoples libraries is akin to being a chef that will only eat their own food.
Can you please go directly to your boss's office and tell him that you are not even close to being in control of the objectives he told you at the convention, that you should have, if you want that bonus we've been talking about?
Somebody who only uses their own code has awful taste in code.
No, that last sentence was way to illfull. Sorry for inventing a new word. It means "full of ill".
I don’t own any software. To the extent I ever have, I rescind my copyright. There. No more problems!
I definitely agree with being conservative about what you use but writing almost everything yourself is a disaster waiting to happen.
> we don’t use libraries. The only libraries we use are where [...] I know the library will continue to be maintained.
I interpreted his point more charitably as "be very selective about introducing libraries". I've had the most success with framework-agnostic, foundational libraries (tables, date-time) and with best-in-class framework libraries (state management, calendars).
Don't ever work for jerks. Yes, sure, it might seem like it's a great way to further your career. But then, one blissful corporate day you find that you've been working for the dark side all along and you'll soon regret it. Don't ever work for assholes. Don't ever work for people who thinks depending on crapware is a good thing. These are not good people.
There are lots of bad JS libraries but there are also some good ones that are mature, well-tested, and supported. Refusing to use them is a waste of time and money.
In the context of security, it's also professional malpractice.
The vast majority of libs that sit on top of React are completely useless time wasters that cost you more in dev time in the long run than writing it yourself. Just React, CSS and the Chrome dev tools is more "power" than like 99% of dev environments that have ever existed. The fact so many garbage front enders think you need to pile 80 more dependencies on top of the bog standard stuff is a joke.
Avoiding libraries as a default and knowing when to make an exception is the most important part of being a front end dev these days. Reaching for libraries as a default solution to any problem (which is what 90% of FE devs do) is a great way to fuck up every project you're on.
I think for those folks, "prefer writing your own 'ReactFlyout' module" is literally not a path forward. Like it or not, those folks make up a large portion of the work force.
There are software organizations that live by a "prefer renting and buying over building it" tenet, for the same reasons that outsourcing made sense to the MBA types. But when you all of a sudden need to render a button differently, or a service goes down, they refuse to take any responsibility for the mess.
I've been burned by a couple of libraries namely because they didn't handle hooks properly or were creating bugs that I couldn't understand.
The conclusion the author makes (only use libraries that are well maintained by a known team) is a pretty good heuristic for which libraries to choose.
tools like snyk.io overviews of most packages show why so many are landmines you're planting, not time savers. if you've never felt that pain... that's interesting. it's odd to not be hit by their issues when things like major upgrades happen (every year or two, right, else you're outside of LTS windows!), routine scans+penchecks, and other aspects of writing code that isn't going to destroy your customers safety + team's productivity.
Seems like you agree with their view?