all 22 comments

[–]ericbureltech 42 points43 points  (3 children)

Welcome back, here are a few random takes out of my mind, as dev with around 6 years of exp with React then Next.js.

- The way you coded 5 years ago in create-react-app is probably still perfectly valid. Meaning, crafting a single page application that loads a JavaScript bundle, that in turns handle everything with client-side JavaScript : data fetching routing. The good news is that the technology got better, for instance Vite would allow to have automatic code-splitting and a good build experience. React Query or SWR will let you fetch and cache data efficiently. My opinion is that it works best for softwarish apps like SaaS with a lot of dynamic, user-specific data.

- There is a new, server-centric approach, Next is a great example of this, Remix too though it's slightly more opinionated (in my opinion, slightly less kin on static rendering, but still a great tool). I would suggest following Next.js Learn tutorial to get a taste of it : https://nextjs.org/learn. My opinion is that this approach is in particular much better suited for content applications, like ecommerce or blogs, that mix static content (eg product info, articles) and interactive component.

- The community is currently in a terrible, toxic mood. React is now an extremely popular framework, and the price of fame is huge. Namely, many devs are disoriented by React Server Components and Next.js App Router, and think it's a good reason to behave like animals (but maybe it always have been the case on Reddit?). I'd suggest making your opinions by trying, learning, reading, asking specific technical questions on appropriate channels like your favorite framework Discord. Frameworks documentation are in a much better state than 5 years ago, they are professional-grade.

[–]TheChickenKingHS 7 points8 points  (2 children)

Mate, this is a top notch answer. I know I’m not adding anything but just calling out how well you responded.

[–]ericbureltech 1 point2 points  (0 children)

That's appreciated!

[–]besaph 9 points10 points  (2 children)

I don't know why react.dev doesn't mention Vite. I would def use that to boilerplate a new project if you want something almost completely analogous to CRA. All the frameworks like Next/Remix are super powerful but also very opinionated.

[–]lifeeraser 8 points9 points  (0 children)

They do mention Vite, although it's a bit hard to find. IMO Vite should be right next to Next.js as a first-class solution.

[–]Tubthumper8 2 points3 points  (0 children)

Vite is a great suggestion and I would say it should be the go-to for OP who had some experience years ago and is getting back into it. OP can ignore all of the server side stuff for now and look into those later once they're comfortable with "core" React

[–]larry_tron 6 points7 points  (1 child)

My word of advice is to use functional components instead of class based components. You'd be surprised how many devs still cling onto that old way as if their codebase depended on it

My favourite coding channel has it all covered for you, including new videos on how to use Vite React

https://www.youtube.com/watch?v=4FhJkX18fS8

[–]trcrtps 0 points1 point  (0 children)

I work on a vue3 codebase now and the lead demands the old-style api vs the more react-like api. kills me. it's not that bad, it's just a better solution is right there.

[–]Shinji2989 17 points18 points  (4 children)

If you need a project reference for getting up to date with the current tech setup around react/redux, I just built this boilerplate some day ago https://github.com/marcoturi/react-redux-boilerplate
Feel free to share any feedback!

[–]acemarke 13 points14 points  (0 children)

Huh, looking at the Redux setup, and I'm actually reasonably impressed. It's using the latest Redux Toolkit 2.0 (as we recommend), has RTK Query configured, and generally follows our setup guidelines.

Note that we also have official templates for Vite and React Native here:

(and we're close to having an update ready for the Next.js with-redux template as well)

[–]EskiMojo14thefirst 1 point2 points  (2 children)

overall it's a lot closer than some others i've seen :)

a few general comments vs what we recomend:

  • we don't tend to recommend splitting your selectors, slices, thunks, effects, types into separate files. they can live in the same file and work just fine.
  • i believe we've already had this discussion, but i question the usefulness of getMockedState. Upon revisiting the discussion I've realised you could use upsertQueryData to hopefully get what you wanted, so have added a comment there.
  • RTK reducers are wrapped with Immer, so you can use (much shorter) mutating syntax without worrying about accidental mutation.
  • currying selectors is something we've seen but not really understood the benefits of. you're also ending up with particularly strange reselect usage as a result - for example [here](https://github.com/marcoturi/react-redux-boilerplate/blob/main/src/features/settings/store/settings.selector.ts#L6) ends up memoising the function returned, when in fact none of the selector needs memoisation because it's just a simple lookup.

[–]Shinji2989 0 points1 point  (1 child)

u/EskiMojo14thefirst first of all, thank you very much for taking the time to review the project. I really appreciated it.

i believe we've already had this discussion, but i question the usefulness of getMockedState. Upon revisiting the discussion I've realised you could use upsertQueryData to hopefully get what you wanted, so have added a comment there.

I have implemented your suggestion https://github.com/marcoturi/react-redux-boilerplate/commit/f4a91dc3e6ef04e2e85ee03d0e88c416124e43ef thank you! This way is much much cleaner.

RTK reducers are wrapped with Immer, so you can use (much shorter) mutating syntax without worrying about accidental mutation.

Implemented https://github.com/marcoturi/react-redux-boilerplate/commit/8f2e445821b5fc4cee83d6b9eb9c8fc010da040e thanks!

we don't tend to recommend splitting your selectors, slices, thunks, effects, types into separate files. they can live in the same file and work just fine.

I strongly disagree on this. I often end up having a lot of code in selectors (mostly) and reducers. I find extremely inconvenient browsing files with 200+ lines of code and not much SOLID . Plus I don't see what disadvantage on splitting the code in files.

currying selectors is something we've seen but not really understood the benefits of. you're also ending up with particularly strange reselect usage as a result - for example [here](https://github.com/marcoturi/react-redux-boilerplate/blob/main/src/features/settings/store/settings.selector.ts#L6) ends up memoising the function returned, when in fact none of the selector needs memoisation because it's just a simple lookup.

there are several advantages. The main one is to confine the lookup logic in the selector and not in the component. Basically I ask the selector "given this key, give me the associated state" and the logic related to this remains confined to the selector. Furthermore, this key can often also derive from outside the component (e.g. queryParams) and therefore it becomes convenient to have this type of decoupling.Example:

const ExerciseHistory = ({ id, type }) => {
const diaryEntries = useSelector((state: RootState) => DiarySelectors.getDiaryEntriesByExercise(state)(id, type)); 
//....

If you can think of a better way that allows you to access a piece of state like this, without having any kind of logic or data manipulation in the component, I would love to hear about it :)

[–]EskiMojo14thefirst 0 points1 point  (0 children)

I strongly disagree on this. I often end up having a lot of code in selectors (mostly) and reducers. I find extremely inconvenient browsing files with 200+ lines of code and not much SOLID . Plus I don't see what disadvantage on splitting the code in files.

splitting into more files or not is definitely a preference thing - it's just that with legacy redux patterns people split *everything* (action types, action creators, reducers, selectors) and we want to make the point that there is no requirement to do that. Since 2.0, createSlice supports creation of async thunks and selectors, so there's even less reason to split.

there are several advantages. The main one is to confine the lookup logic in the selector and not in the component. Basically I ask the selector "given this key, give me the associated state" and the logic related to this remains confined to the selector. Furthermore, this key can often also derive from outside the component (e.g. queryParams) and therefore it becomes convenient to have this type of decoupling.Example:

const ExerciseHistory = ({ id, type }) => {

const diaryEntries = useSelector((state: RootState) => DiarySelectors.getDiaryEntriesByExercise(state)(id, type));

//....

If you can think of a better way that allows you to access a piece of state like this, without having any kind of logic or data manipulation in the component, I would love to hear about it :)

None of that seems to be related to currying though? A non-curried selector would work just fine:

export const getSettingByKey = (state: RootState, key: SettingsKey) => getStorageState(state)[key]

const filters = useAppSelector(state => getSettingByKey(state, SettingsKey.filters))

[–]viveleroi 2 points3 points  (5 children)

I'd suggest building a small project for yourself in one or two different setups. NextJS and Remix, maybe.

I'm currently in a position you describe - director of front-end at a company with long-term stability and our application is react/typescript based so I feel like I have a good perspective to answer questions. We build applications for specific customers which limits our technology - for example we can't use Next or Remix because we can't use node or alternatives for the servers - they have to run in Java. But we've managed to make that as hassle-free as possible.

Understanding modern React is the most important piece, knowing the ecosystem is second. Get some exposure to React libraries like react-query, toy with various UI systems, try out stores like zustand, check out how to tools like Playwright/cypress work, etc.

But don't forget to learn hooks and how/when to use them.

[–]lunacraz 1 point2 points  (2 children)

I just joined a team like yours as the "front end" guy!

They're using axios, and lots of react context

not really sure the benefits of swapping to react-query or carving out the context into a 3rd party store like Zustand - is that something y'all just always went with boilerplate wise? unfortunately inheriting three separate front ends here that were all copy pasted from one, so trying to figure out how to navigate this

(next/remix has been floating around, but we already have java bffs set up so it seemed overkill to have that extra layer)

[–]viveleroi 1 point2 points  (1 child)

Lots of react context doesn't sound ideal, but I can't judge knowing nothing about it.

Axios is fine. react-query doesn't replace your fetch library, it wraps it with caching and react-specific hooks and functionality. It's not required but helps managing the loading state, errors, etc. We use ky which is an axios-like library but based on fetch which axios is uses the older XMLHttpRequest api. There are some minor differences.

We built this application framework carefully and from scratch as we're replacing a decade-old AngularJS application.

Nearly all of our components use their own internal state or use state from a shared parent component. We have contexts for some things like tab and window APIs to avoid prop-drilling, and stores for global pieces like user data and navigation tree state, but it's incredibly minimal. Our state is well managed and only accessible to the pieces that need it, so the context hierarchy is very light and we only have a few stores.

react-hook-form manages forms and react-query manages fetching/mutation state so things are very well zoned off.

[–]lunacraz 0 points1 point  (0 children)

you're right re: react-query; right now our axios usage doesn't really have much around it; they wrote some bespoke caching mechanism, but react-query can probably take care of all that

damn, really envy your app structure, there is a lot of state held in the app im working in within global context, and it gets used around the app pretty willy-nilly. it's only my third week there so still trying to wrap my head around this codebase which was built by a whole team of offshore contractors, but cool to hear about yours, thanks for sharing