This isn’t meant to be a guide on how-to React. I just want to share some of what I’ve learnt during my time working on a Single Page App (SPA) for my current company. We’ve made a lot of mistakes, and we’ve learnt from them. So, this post may not be perfect. If you find something out of place, feel free to let me know.
Language
From the get-go, we decided to go with TypeScript. There was quite a debate amongst the company as to which language we should choose. Do we go with plain JavaScript, or do we go for a slightly more IDE friendly language like TypeScript? Well, we went for TypeScript, which has its pluses and minuses. Firstly, I would like to say that it’s an excellent language for IDEs. Having classes, interfaces, and general static typing helps a lot. It helps developers understand what the actual class looks like. It lets us stub away interfaces while another developer works in parallel on it. It makes it pretty easy to test.
There are, of course, negatives to TypeScript. What happens when you come across a package without types? Well, you have to define them yourself. What happens when you come across a package that doesn’t have everything typed? Well, you have to redefine the whole package yourself. You also have to add Types to all your code. Not everyone is a fan of that.
Structure
When we first started our app, we had a traditional structure. More like what you would expect from a .NET project. We had a /tests/ folder, a /styles/ folder, and a /scripts/ folder. This was when we started. We also started out with the Karma JS test runner and chai. I’ll get deeper into testing React on my next post. To continue, inside the /scripts/ folder, we split out into /pages/ (each page in the SPA), /components/ (kind of like our shared components), and /services/ ,/utils/ etc.
Long-term, this structure is not sustainable. We have started to move away, into more component-based thinking. We believe that having a sustainable SPA will consist of only the source folder. In it, we have a folder for /apps/, here we put our React hooks as we now have multiple apps running almost the same code. The only other folders are our domain folders. You only may have one domain. We have a couple: like inbox or host. Inside these domains are the component folders. Each component has it’s .spec files, it’s .sass files, and potentially child components. You can also sub-domain your folders at this point into things like your separate pages as they’re mini-domains themselves if they’re complicated enough.
Build
We’re using Webpack for the build. There are plenty examples of Webpack online. We have an entry point for each of our apps that we use which allows you to reduce your bundle size while having a single source of code. This has allowed us to share components easily, while also maintaining domain boundaries. We started with Webpack right at the very start and haven’t found a need to switch yet. Although I have heard, it can run quite slow now though.
We use a TSLint, as well as a TypeScript parser. We can load files referenced in our TypeScript and create a package that contains all those files referenced and deploy that to our CDN. We use SASS, so we have a SASS parser before we make it CSS and then we minify both the CSS and the outputted JS.
Components
We learnt early on that the more dependencies your component has, the harder it is to debug and maintain. Most of us came from an Angular perspective, so it was a little bit of a difficult transition. What it boils down to is: use as many stateless components as you can. Minimise the number of stateful components you have. If possible try to make the most stateful components the highest level.
For us, that was a page component. A page component called the server to get the data, and then it filled out its form. We originally programmed nearly every component as having a state. I mean, why not? A text box should keep track of what text is stored inside it right? Wrong. If you start thinking like that, then you’ll end up with components that can’t just be dropped somewhere else. The behaviour will be odd and buggy at times. The state should be stored at the highest level. The logic should also be at the highest level.
But how do you update a parents state from a child component? Isn’t React only one way? It’s true, with React you should kind of think of it like a waterfall. Data should fall from the parent to the child. However, you can add something to your props. You can use JavaScripts inbuilt functional aspect to pass through a method. An update method.
import * as React from 'react'; import { Button } from 'react-bootstrap'; interface MyProps { onButtonClick: () => void; } export const MyComponent: React.StatelessComponent<MyProps> = (props) => { return ( <div> <Button onClick={props.onButtonClick} /> </div> ); };
As you can see by the onButtonClick, we pass through a function from the parent that can be accessed by the child. You can do this with any input, or any component you wish to make. You don’t need Redux to create a functioning SPA. But, more on Redux in another post.
Summary
I’m not sure if I’ve gone through everything you should know. But, choose a language you’re comfortable in, and that will make it easier for you and your team. Make sure you structure your React app so that it’s more of a component-first model. Don’t fall into the trap of separating tests, styles, and everything else. You don’t need to. Use an excellent build tool. We use Webpack, but I’ve noticed a few others popping up now. Finally, try to make as many components as you can stateless. Trust me; it’ll help long term.
Reposted on Medium.
Leave a Reply