I work as a full-stack developer for an electrical contractor in the construction industry. I'm self-taught, and I've only worked with one other developer for a few years, who taught me what I know, but now I'm the only developer.
The company I work at is a Microsoft shop through and through. We do React on the frontend, ASP.Net Core with Dapper as our API, and MSSQL server (2008, and just barely moving over to 2016) as our database. All of our stuff is hosted on-prem behind a company firewall, so we use a mobile VPN so our field personnel can access our apps on their iPads. Here is the real kicker, we use Windows Auth instead of our own Authorization or a third party service.
The ideas I have for this skunkworks type project are purely based on my knowledge and skills, sprinkled in with a little hopes and dreams ;].
Lately, when I'm developing a new feature or a new project, I run up against issues with React that I wish I could wave a magic wand and make go away. Most of the time it's tracking down why the hell this component keeps rerendering. Other times it's deciding how my state should be structured. But on the occasion, I find that I need to refactor a portion of my code-base because what I thought would work at first just doesn't.
Getting back to the fact that I'm a solo developer in a developer wasteland, I don't have many people to bounce ideas off of. I think most of the time I get caught up on developing an opinion on how projects should be structured? Should this state be in Redux or only local? Where do my custom hooks live? Why is managing API calls so difficult sometimes? These frustrations boiled over recently and I compiled a list aspect that I would fix if I had my own framework.
Admittedly, these issues could be non-issues and I don't have the proper skills/knowledge to deal with them effectively. So this project is more of an exploration of how web frameworks work and develop my skills further. I don't expect it to become the next React, or even be used.
A lot of the issues I'm going to list will revolve around React not having a built-in utility for or a strong opinion on. I'm sure a lot of people like it this way, but sometimes I find it to be a challenge to deal with in specific projects. Here is what I typically have issues with:
There is no single way to manage state effectively. I'm talking both local and global. Yes, there are many ways but they all seem to have trade-offs. I don't care for prop drilling but sometimes the state is so small that it only makes sense. Other times I feel forced to put the state in Redux because prop drilling would be ridiculous especially when it's just a boolean that controls a modal.
The biggest trade-off that a lot of people have tried to solve is the boilerplate issue. I understand why I have to write a bunch of code to manage global state, you'll never get away from writing something. You have to write something, and that something mostly is state. But you have to be careful about how you structure that state because bad structuring can cause other components to re-render when they shouldn't.
Communicating with sibling components can be a pain because there is a knife's edge on whether you go with prop drilling or Redux actions. For instance, I have a table row that triggers a side panel to open up with more information about the row. Sometimes the table row is deeply nested and it's obvious you go with Redux. Other times the nesting difference is only two and you have to decide between Redux or the parent holding the functionality.
I don't really care for components holding functionality that they aren't concerned with. The parent's only job is to pass this functionality to its children because the children themselves can't talk to each other. This doesn't feel right, I feel like components should only hold functionality that they are concerned with.
Dealing with API calls can be very messy. Let's say you have a form that you want to auto-save after updates. But you know your users are typically in a low signal environment and will likely have failed API calls. So you either implement some way to have an offline failover or you create a Saga style pattern of undoing the changes the user made, which is terrible user experience. Or you give on auto-save and bulk post the data and add a save button.
What if I have data that I get from a GET request, purely informational doesn't need to go in Redux, and this data is used in a bunch of different places in the app? Implement data caching. You need to update the cache because the data got updated from the database? Screw it, throw the data in Redux, and add Redux-Persist.
A lot of data fetching and handling usually ends up in Redux even though updates to the data are outside of the current user's control. I prefer only actionable data lives in Redux but it gets the job done.
I've never really cared for the container/view component model. I understand the validity of it and that if done right you can use your container components with React-Native and BAM! you're cross-platform. On the flip-side, I don't like bloating my components with tons of hooks and functions. I like to abstract it out into a custom hook, but where do I put that? How is it different than the container/view model?
Component re-rendering is a big issue I deal with more often than I should. I really wish I could get my components to render just once with all the data needed. Using the Dev-Tools I don't get many answers because all it says "Props Changed." Unless I install "why-did-you-render" and add it all over the place I'm out of luck. This is one of the situations where I wished the React tooling in development mode gave me all that information.
Well if I had that magic wand, I would probably end up with a cross between Svelte and React. Why not use Svelte? Because I'm big of JSX, it just feels right, and I'm not a huge fan of the handlebars style syntax in Svelte.
So in detail this what I've been thinking of as reasonable solutions.
As I said, I love JSX, but I don't think it goes far enough. Personally I would abstract away all HTML elements like so: div, span -> Container; p, h1, h2... -> Text, etc. I think the major benefit of this is that you can provide standard pre-styled components like Flex and Center. On top of that because all elements are abstractions you can switch out your build engine so it can build to web, iOS, or Android.
Although I haven't put much thought into it, I would go with a more opinionated way of handling component styling. I think the current landscape is great and there are a lot of great ideas being used but I would like to see some convergence on a particular method.
Another thing, I would do away with the Virtual DOM and immutability. Maybe I don't understand the benefits enough, but I feel like sometimes I hit race conditions that are hard to diagnose, or the state comparison algorithm creates too much overhead and really bogs down the application.
I would like to see some sort of event-based system where components have action channels that other components can talk directly to. In these channels, you can have multiple listeners so one action can trigger multiple other components to update. This would act as more direct communication and not like Redux where actions are passed to every reducer to see if there is a match.
I wouldn't do away with the ideas of global vs local state. In my mind, I see it stylistically like class properties where you have public and private properties. These properties can be static or read-only, and they can public/private which determines if other components can read them. So public properties would be akin to global, and private is local state. By doing this we can reduce boilerplate for our global scope.
I would want a standard component that abstracts away the more tedious aspects of data fetching. The more tedious stuff being call debouncing/throttling, polling, short term cache so data can live through refreshes, pre-fetching, and progress updating. Though I wouldn't want to abstract too much away because the user still needs to control the authorization and other headers.
I think it would be awesome if you had a choice between building your app to a Single Page Application or a Multi-Page Application. I understand there are a lot of benefits for SPAs and the ability to use them as Progressive Web Apps. But what if you're more concerned with bundle size? Yeah, you can split up the bundling with Webpack but I think there benefits of MPAs.
This Multi-Page Application style would be slightly different than your traditional MPA. What if you can make API calls to get server-side rendered components as a string or as a data structure? Then you can use that API call coupled with a super lightweight renderer to render the component and attaches itself to the event system. Or what if the event system was server-side and the frontend only had the lightweight renderer.
This could get us a step closer to a more native approach to Micro-Frontends and I think feature flagging or A/B testing would be easier to handle.
I wrote this article to get an idea if anyone else feels similar in dealing with React. At the end of the day, I still love React. It's an amazing framework, and I'll reach for it every time it makes sense. But I believe the issues I talked about really hold it back from a perfect developer experience.
I'm slowly working on the overall design of this framework and I might write another article once I've made more progress. But for now, I just wanted to see if these ideas are interesting to anyone else. Would anyone want to work on this?
I don't know, am I off the mark? Are there some obvious aspects I'm missing that would make dealing with these issues easier. Or are there other issues that you deal with? Let me know!