So I was trying to make a super simple app with react and firebase, using typescript. Basically an app that lets you login to see some authorized content.
The application state for this POC was extremely simple:
{
user: { id: string, name: string },
isAppReady: boolean
}
Initially the backend was going to be written with .NET so I used their CRA (create-react-app) template, but later I switched to java. Anyway, like magic, I had an app that worked and even communicated with a backend. Yay! I noticed that there were a like a billion dependencies in this web project, but surely I wouldn't have to understand a billion libraries for this simple project and I could clean them up later.
Next, I added the firebase dependency to my web project and configured it with my backend instance and everything was still good.
Then, I created a LoginButton that let me login and added it to the nav menu. I figured out how to share objects via context providers and I was able to prompt for login. Woo!! I'll be done in no time.
Now, I have used JS for many, many years, but unfortunately, was late to the whole ES2015 fiasco while working at a large company for a few years (staring in 2014). But when I came back to the real world, I was hit with a rude awakening as to the state of front end development.
But you know, that was no biggie. Things change, and I got back up to speed and started working on a SPA app for another company (I wasn't a NOOB to SPAs then, nor am I now). I didn't choose the framework there, but I used one whose reactivity model was based on browser events (with a manual hook available), so it was pretty simple to work with.
Later I migrated to vue and it was simple to work with. Now in deciding between using vue, angular, or react, I previously eliminated react because the last time I started creating a react app, I had to install like a billion dependencies just to do something simple, but now for personal growth I decided to give it a try again.
Ok back to the app. I don't want this to be a rant, but let me explain what happened next. I noticed that the user was null on startup because firebase.auth
does not completely initialize on creation. So I needed to update my app's state when firebase became ready. And this is where everything fell apart.
First, I'm like "it's time to REALLY be a react dev". Cool. Since I needed state management, I needed to learn redux. This was expected. But then redux is not react-specific, so I needed to learn react-redux, ok..., which sent me to redux-toolkit. Then because I was dealing with asynchronous logic, I had to learn what a Thunk was and how redux-thunk works. So now I'm like... seriously, wtf. Now sure, maybe I could have abandoned this architecture and started using MobX or something, but I feel like react/redux is the standard for react. Maybe I'm wrong.
Ok, so I have to learn all of this and organize it in my mind so that it makes sense so that I can actually use the acquired information. And that's way too much complexity IMHO for such a simple task. After I use up my mental bandwidth learning how to update a user asynchronously, I fight with the type annotations because in my starter cra template (remember .NET), I guess the people at MSFT also did not fully understand the interaction between the libraries/frameworks (ie react / react-redux / redux-thunk). There was a bug in the code, however, instead of fixing the root issue, they simply removed type checking by asserting the component as any
.
export default connect(
(state: ApplicationState) => state.weatherForecasts, // Selects which state properties are merged into the component's props
WeatherForecastsStore.actionCreators // Selects which action creators are merged into the component's props
)(FetchData as any);
Who knows why they worked around it that way, but there was definitely an error with their typings. I was confused as to why I was getting compilation errors when I tried to connect but figured out they were incorrectly typing their components.
I digress. So I correctly type my component, so that I can connect, so that I safely dispatch my action, so that I can update my state, so that the component refreshes. But now I am aware that I have to repeat this process for every new component that communicates with the store. Mainly update the component interface, create the actionCreators and reducer separately, then link them (with a switch/if/etc in the reducer), and manually connect the component to the store.
So that's not DRY and is unacceptable because I don't have to do that in other frameworks. For example all components can use the store with this one line in vue
Vue.use(Vuex);
This is not to promote vue, but to say I feel like the time to actually do something efficiently and correctly with react is way higher than with other frameworks that I've used and I feel like I've stepped back in time. Since I know I could write something to eliminate this duplication, I'm sure there's a better way. But again the problem is not that it can't be done, but that the time to do it efficiently and correctly is higher.
I haven't even started applying middleware to my routes and error handling, but if I have to include another 4 libraries just to add access control to my routes (before actually implementing access control), then I must say, its starting to look like react development is slow and tedious.
I'm curious as to what others think.
Top comments (0)