Yesterday, I completely removed any trace of React (and Typescript) from a project that I’ve been working on for a while (Non-Profit Link). But why?
It’s probably easier to tell you why I wanted to use React in the first place, and why those reasons were half of the motivation for me to remove React: Scalability, reusability, and, embarrassingly enough, just to be able to say that I’ve used React in a larger project.
Scalability ↗
Admittedly, I was a little bit hyper focused on the potential scalability of React. The components, strongly typed languages (as long as you’re using TypeScript, of course), and the overall neatness of it.
Well, lesson learned. Just because something can be scalable doesn’t mean it’s good for you or your project. Components are awesome, but only when you really need them. TypeScript was cool, but overall slow and obnoxious to work with (just in terms of this project, I still love strongly typed languages).
For example, this is just for a singular img element in a component!
export interface imgsInfo {
img: string;
alt: string;
link?: string;
}
And yes, React is neat and tidy, but that’s just more to manage.
Reusability ♻
Components are reusable, right? Right???
Sure, but that just means more files. More imports to manage. More things to make TypeScript lose its religion. More interfaces and props. Being able to reuse stuff is nice, but I simply didn’t need this amount of reusability.
“I used React with Django!” 📄
That’s what I wanted to be able to say, at least. But again, lesson learned. Just use what’s best for your project. Don’t worry about what might look good on a resume.
The other half of the “Why” ❓
Not to place the blame entirely on React, as I was the one who was absolutely starstruck by the ✨ scalability ✨ of React, however those features that I just mentioned were part of React. So, while I would like to completely blame React, that just wouldn’t be fair.
But anyways, onto what I was solely at fault for.
Django and React don’t like each other 🐊
Getting Django and React to play nice is like throwing a crocodile into a cage with a gorilla, and then telling them to shake hands and discuss the current economic situation of the world. They just won’t, and there’s no way to make them peacefully work together.
So what do I mean by that, in the context of Django and React?
The Two Options 🤔
I should first clarify what my two options with Django and React were. Either completely separate the frontend and backend, and communicate to the frontend through the Django Rest Framework (DRF), or use a bundler like Webpack to bundle your JavaScript (TypeScript, in this case), then load the JavaScript into each template.
The problem with using the DRF is that you get none of the advantages that come with Django.
For example, Django comes with a pretty sweet templating system. Without explaining it in depth, if you want to pass data from the server to the client, you can simply pass context to the template when you render it. In case you’re curious, it looks like this:
views.py:
return render(request, "index.html", context={"test": "test"})
index.html:
{{ test }}
Ignoring the imports in views.py
, and the header info in index.html
, it’s a grand total of (roughly) 2 lines!
Django also comes with user authentication, session management, and more. All the good stuff that makes development go quickly and smoothly.
I decided that if using the DRF removes all of the good stuff about Django, I don’t want to use it. So, I decided to use a bundler.
The bundler (i.e, the main issue) 🧵
This sounds like a pretty good setup, right? Well, I thought so, and I was incredibly wrong!
I could try and describe to you why this doesn’t work all that well, or I could just give you an example. So, let me show you what adding one <h1>
element to a template named index.html
would look like:
Add a div to index.html
like so:
<div id="react-header"></div>
Then, go to assets/pages/index.tsx
. Import any components that you need to make the header (in this case, none), then write this code to render HTML in the specified div:
ReactDOM.createRoot(document.getElementById("react-header")!).render(
<React.StrictMode>
<h1></h1>
</React.StrictMode>
);
Ok, we're done now, right?
Wrong. Now you need to transpile and bundle this code with Webpack (this took about 10 hours to get set up):
npm run dev
Webpack is kind of nice, as it does the transpiling and bundling all in one go, but it's still a pain.
Bundling can take anywhere from 1 second to 7 seconds (or more), and then, and only then can you see a <h1>
element appear in the rendered template.
By the way, before you do any of this, you would also need to create and then work out the inevitable little problems with these files: webpack.config.js
, tsconfig.json
, declarations.d.ts
, and .eslintrc.cjs
.
As you can see, this is… incredibly painful, tedious, and overall, not a great idea.
So I removed React. Contrary to how long I thought it would take, it actually only took about 3 hours. And it was definitely a good decision.
Moving forward ⏩
As I learned, you shouldn’t just use something because it’s intended to work well, and you certainly shouldn't use something just so you can say that you used it.
Please do check out what the codebase looked like before and after I removed React. You can compare the differences here (commit before the removal of React) and here (commit after the removal of React). And guess what? The site functions just as it did with React, with at least 30 fewer files.
If I need a lot of functionality in the future, I’ll probably look into something like HTMX or Alpine.js. Otherwise, raw HTML, CSS, and JS are plenty sufficient.
What do you think I should’ve done differently, if anything?
Contact me:
oscar.gaske.cs@gmail.com
Github
Top comments (41)
The point of taking time to write TypeScript types is maintainability. Imagine this scenario: I just joined your project. I clone the repo and start playing with it. Without the types, where do I go look for, well, the types? Which properties does the data carry? Did you document this elsewhere? Probably not. TypeScript is your friend.
Typescript is a “transpilation”-time type checker. It can certainly be annoying or slow (probably both) to work with.
I do, however support d.ts files which can help you notate types in a Javascript project.
I think one of the most common issues is changes / refactorings. Change a function to take an extra parameter; how do you know you updated all the call sites? Even ctrl+f / grep can fail if you take into account indirect calls.
This is just an example, another is returning json from a database query. How are you sure the columns comply with the endpoint schema? Maybe an update made a field nullable?
Typescript is ridiculously slow
Typescript slowing down a Django project is really not the problem...
Yeah it's a skill issue
TypeScript is your friend for types, sure. But how often do you actually have ambiguous parameters where the exact type matters? Especially when using it with React. The fix for this shouldn't be dev overhead in writing more elaborate code-as-documentation. It should be writing clean and concise documentation, and sorting out parameter naming such that it tells you what you need.
Unsure about what you mean by this.
So you believe exchanging TypeScript, a concise and precise method of "documenting" as you say, that can be parsed by a computer, that can be used in CI/CD to catch errors and that can be used by IDE's for code completion and faster development, with some MS Word or Markdown README file that computers cannot parse or understand, that cannot help with CI/CD and that IDE's cannot use to help you write accurate, error-free code is in fact the better choice?
I certainly see your point on bigger projects. I think my overarching issue was that TypeScript was just unneeded in the first place.
TypeScript is a God-send for application development, and you won't appreciate that until you work on a decently large enough project (it doesn't have to be too large even).
Types are extremely useful for maintainability and scalability. Ditching typed languages just because working with an untyped system is faster/easier tends to bite you back later.
Also, I didn't understand your arguments against React. If you want Django's templating system then why are you even considering any frontend framework at all? Frontend frameworks and a templating system of any backend framework are mutually exclusive.
The same goes for reusable the reusable components argument. React (or any framework) doesn't force you to break your components into reusable chunks. If your project is small enough that large components are better than reusable chunks, then work accordingly.
I honestly struggled to see any fact-based reasoning here. This seems 100% a preference thing. You don't like TypeScript, and you like Django's templating system.
It's not that I don't like TypeScript, it's that I failed to see that it was not a good fit for my project. As you pointed out, types are extremely useful. But that level of "scalability", so to speak, is just unnecessary for a project as small as mine (and with no plan to grow to a much larger size).
Also, there really shouldn't be any fact-based reasoning in the first place; the only true "facts" present in my post is the fact that React has reusable components, and that Django and React don't play well together (and even that's a bit of an opinion).
Overall, it's just been a learning experience for me. Don't use the stuff you don't need, and put some thought into what that stuff is going to do for you in the long run.
I found Typescript to be worse in bigger projects, mostly because developers turn every, single, file to a type enumeration file. Type here, type there, it's a mess. I do agree with your point about React.
What makes type declarations a mess I don't get it? Why is a type messy and an object not?
Types extremely help with the navigation inside a codebase. You can trace a type to all its usages, and if you mess up in one of your usages you get an error and won't need to go on a wild hunt to find that bug where you misspelled a property.
You can know the output of a function you haven't seen in 6 months by hovering over it, not by reading its code.
Without types you have to document everything. JSDocs are fine if you like them, but you haven't seen mess until you looked at JSDocs everywhere. And you have a messy codebase if you neither have types nor documenting comments.
he Power of TypeScript Types for Maintainability: A Detailed Look
You're absolutely right! TypeScript types are incredibly valuable for maintaining code and ensuring a smooth developer experience. Imagine yourself joining a new project:
Without Types:
You clone the repo and start exploring the code.
You encounter a function called processUser(user) but have no idea what properties the user object contains.
You dig through the codebase, searching for clues about the user's structure.
You find mentions of properties like username, email, and age, but there's no guarantee these are all the properties.
You may encounter unexpected behavior or errors due to missing information about the data.
You might need to ask the original developers questions, potentially slowing down your progress.
With Types:
You clone the repo and instantly see that processUser expects a user object with clearly defined properties like username, email, and age.
You understand what data the function operates on, making it easier to write correct code.
You can navigate the codebase with confidence, knowing the structure of the data.
You can use IDE features like code completion and type checking to write faster and avoid errors.
The code is self-documenting, reducing the need for additional documentation.
New developers can onboard quickly and contribute to the project seamlessly.
Here's how TypeScript types specifically enhance maintainability:
Clarity: Types explicitly define the structure of data, making it clear what properties are available and what their values can be.
Improved tooling: IDEs can leverage types for advanced features like code completion, type checking, and refactoring, leading to faster and more reliable development.
Reduced runtime errors: Type checking catches errors early during development, preventing crashes and unexpected behavior.
Easier onboarding: New developers can quickly understand the codebase and its structure thanks to clear type annotations.
Safer code changes: Refactoring and code modifications are less likely to break functionality when types are present.
Better documentation: Types act as self-documenting code, reducing the need for additional documentation and comments.
Investing time in TypeScript types may seem like an overhead at first, but the long-term benefits for maintainability, developer experience, and code quality are undeniable. It's an investment that pays off in the long run, leading to a more robust and sustainable codebase.
Hi Oscar !
Nice post! I did the same thing a few years back, at the time, i was a django developer and python was my strong suit. I needed my application to have async refreshes in the FE, so instead of doing ajax and all that hardwork. I split the BE and FE, and adopted react for the frontend. This was perfect solution for me, while I wanted from django was the ORM tools and from React was the asynchronous capabilities.
Fast forward to 2023, I have adopted React (mainly Next.js with Typescript), so it might take some time to get used to JS frameworks. All the best !
Ah yes... I love this.
As someone who has used both Django and React in project when the premises of combining the two hit my radar I was very skeptical about it. As such, never tried to do it.
As for the comments praising Typescript, I've already written an article about that; so I'm not going to touch it
I've worked on some pretty big projects at several companies, and IMHO the easiest is to have your front-end and backends separate. You can deploy changes easier, especially if you have a lot of tests and a CI/CD pipeline. You can manage your team easier - front-end ppl on the front-end, etc. Even if you don't have the team, setting up DRF with token auth is a breeze and is easy to integrate with a standalone frontend. I agree auth is the big reason not to do this, especially if you have keycloak or another auth provider you are using. All in all, I recommend the separate apps over integrated apps, especially if you have a complicated front-end. If your front-end is simple enough though, you should totally go with your backend templating.
You could use something like inertiajs.com. It was built for Laravel but you hookup with any framework using adapter like this one for Django github.com/inertiajs/inertia-django
I had a guy I worked with years ago.. The project was written in PHP, it was his first programing project that paid him $$$$. It was so heavily oriented towards everything is a function, rarely did the functions return values, alot of void methods passing references all around the place. Once I got into the project I realized I was in shitshow land. I told them we may gain more momentum rewriting this project by defining our table contracts / etc.. in a new framework. Go with something SPA based. I learned later that the product was used in the education industry & by many nonprofits which had computers often times so old that they didn't even work with modern javascript. I was pretty annoyed, and the product kinda fit the times -- sort of.
Moral of this story is, the best product is the one that works for you. Period.
If you're a single developer and you make headway without using React + webpack + etc tooling, then that is your way. If you make alot of progress using react + webpack + etc tooling, then bygolly, use that toolchain and make some cake. But lets not bully people for using what makes them productive, but we can call out their reasoning, and ask for some honesty. If you like something better than something else, just say it, and be like.. I was more productive this way, it reduced my cognitive overhead and I could sleep at nite and feel productive every time I added a new feature to my product.
Consequently though, if you release your product and feel like nobody is contributing to your project, there is a consequence to choosing to be less modern. It also means you'll have less contributors to your project, and maybe less young / green developers will be interested in learning the ways of old. So go and be productive in your old ways, just realize that sometimes people want their Tesla, and their Rust programing language (nothing wrong with rust).
Yet another "I switched / moved from x to y". Here's some ideas to mull over.
What framework / stack does the developer have the most experience with and can it be used for the project? Why add React in the first place? Sounded like you had stability / maintainability concerns with your current stack. Did those concerns get resolved when you removed React? Sounds like you decided the effort to use React wasn't worth it.
How experienced is the developer. Learning curve for some concepts is just overkill for many projects. Complex ideas are useful when solving difficult problems but just add extra effort if they are just being used without any payoff
What are you building? A basic HTML site or a highly interactive WebApp? Building a basic home page can be done with notepad and a basic understanding of html and css without any javascript.
All these types of articles boil down to the right tools for the project and developer
You hit the nail on the head with your conclusion:
React isn't bad. I'd love to use it in the future (with a codebase that's maybe a little bit more optimized for use with TypeScript/JSX). It just wasn't the right fit for me.
For me, this type of articles is really nice way to see what other developers are really encountering in their journeys. It's not saying this tool is bad or _here are ten reasons why you should/n't use xyz _, it's just some small piece of experience.
I really like how you state reasons why you wanted to use React in the first place, and you just share how you found out it's not a good fit for your project (you + tools you want to use). Thanks for that, @kurealnum!
If the application is mostly server-side view driven, which is what the article is about and what you've been talking about, then indeed there will be very little javascript. I've been instead thinking in the framework of a heavy client-side application, because that's what I've spent most of my frontend work in, which is contrary to the article. Also, I'm biased because I heavily prefer a statically-typed language over a dynamically-typed one.
I was using rails at a previous job, and like Django applications you definitely want the server-side views to do the heavy lifting as you mention. Depending on how much javascript you need to write, I would feel good using javascript instead of typescript. As soon as I'm writing several functions that need to share some data type, I'm going to want to use typescript. But the application may not need that frontend complexity.
There is also the added build step of typescript that otherwise potentially needs no "building". I think this is the most inconvenient part of typescript. The coding experience, in my opinion, is immensely improved over javascript, though it really only becomes "required" (in my mind) when you start having multiple files doing things.
I'm also just used to reading a lot of typescript in general that it reads like english to me, which I imagine is how python is for you (which is literally much more like english, than js/ts :)).
Also I'm curious if you typically write e2e tests or mainly unit tests, or any other kinds of tests. I try to make sure I prioritize e2e tests, to make sure I have coverage on many full happy paths of the application.