Over the last year or so I’ve been pushing to rewrite our maps @ Gogobot using React.
Our current JS stack includes Backbone.js, require.js and a lot of jQuery and I felt like we can do a really nice overhaul and improve the performance of the maps quite a bit. This will also allow us to be more flexible and improve the maintainability of the code. Wins all around right?
The JS world is filled with Buzzwords and solutions that aren’t really built for production. TODO list instructions will not help you really launch anything that is scalable.
Since Gogobot has been in production for over 5 years now and is being used by millions of users, there’s no kidding around here. Once you launch it will get used by devices and users in way you couldn’t even imagine
So, I collected some tips/tricks and general observations which I will write here in no particular order other than what I can think of at the moment.
Redux
I feel stupid even mentioning this. I think it is the de-facto standard for building uni-directional application these days. I am seeing mobx gain some traction and it definitely looks interesting.
Managing the state with Redux means you are working with pure function to dispatch actions and manage the state.
What this means basically is that at any given moment you have a POJO representing your application state and once a state is changes components that are reading from the state will re-render.
I won’t go too much into Redux since this post is focused more about successful adoption of the stack in production.
Read more
Redux-Saga
If you’re using Redux (and you should like I mentioned earlier) in a complex application Redux-Saga is an absolute god-send.
If you look at the screenshot I posted you can see that I have a map on the right side and a list of items on the left side. When the user moves the map it will refresh the list (and the markers) on the map.
Even though those components are not coupled together obviously, the action that is being dispatched needs to handle too many things.
With Redux-Saga you can have “workers” that will basically listen to actions and dispatch other actions in order.
The great thing about a saga is that if the user moves the map while the action is still in progress it will take the latest move of the map and dispatch it through the pipeline.
Take a look at this example from the docs
One more example from the Gogobot application
When a user changes the filter I want to store those filters on a cookie or some sort of storage that will persist for the user (for next visits). Once the filters are changed I also want to refresh the list and send the filters to the server as the param. This is a great use-case for a Saga.
Smart/Dumb — Containers/Components
I’ve seen quite a few naming conventions for these. Whatever you want to call them, you need to start adopting and using them if you want your application to be good.
Here’s an example
This is an ItemList component and this component receives the state from the application as properties. Meaning when the state changes this component (and all children will re-render).
However, ListItem (that is being rendered by this component) doesn’t need to connect to the state, it just needs an item as a property. Plain Javascript object that will be passed either from the parent component or in testing.
Seeing this, you now understand why it’s also called Containers and Components, since the Containers are smart but the Component are only really HTML and style holders.
The reason I love working this way is because I can develop truly decoupled components, I can easily test them and render them anywhere I want in the application.
PropTypes
By far the most underused feature of React is PropTypes IMHO.
It’s weird because React encourages you to develop the smallest and most reusable components possible.
PropTypes are essentially property validation for React components. You define what type of properties the component is expecting, whether it’s required or not.
Example of this
I have a component called “SubmitButton”, since this is a “dumb” component it actually needs the click function to be passed from the containing container.
I think after my 15th component I started including these in each and every component. Get into the habit of using these. It will save your life.
Read More:
Structure
Each and every single tutorial out there will show you the structure grouped by types. You have “components”, “actions”, “reducers” and so on.
This very quickly becomes a hassle. It makes change harder and it makes deleting features/component MUCH harder. We don’t want that.
It is much better to keep the naming by feature.
Now, if you want to remove this container or change anything related to this container it’s much easier to find, much easier to reason about and much much cleaner (damn, so many much in a sentence, that’s a world record).
ShouldComponentUpdate
You can argue for days whether the default value of true on this function is actually reasonable or not. I will definitely NOT go into this argument BUT, you should know that it is.
This little function is invisible to you, you don’t see it, but you feel it’s effect in a very real way.
The image below represents your application, each component has children and those children will re-render if the parent component re-rendered.
Couple of things regarding ShouldComponentUpdate.
- Use it in the most higher up component as possible. Using it in the bottom component will not give you a lot of benefits. using it in a component that in turn will re-render 20 other component will.
- do not compare props and nextProps with !==
- Use ImmutableJS in order to hash the props and nextProps into an easy and cheap deep comparison of the items
- Use 1–2 objects at most to decide whether the component needs to re-render or not. If you nee more, your component is too big and you need to split it.
I’d say #0 on this list should be to actually use shouldComponentUpdate, but I think you figured it out by now.
Development tools
React and Redux both have separate developer tools available for chrome. Those are really helpful when you are looking at things and checking whether a component is updating or not.
Testing
Adopting a TDD workflow from the get-go will allow you to have a cleaner and better code.
If you look closely at this spec file you can see the container/component tip implemented, you can also see 2 methods for testing (component name and class name).
Involving other team members
Getting other people on the team involved sometimes can be challenging. Getting them excited and working with the new framework is critical for the success of the transition inside the company.
At Gogobot, we have a concept called “Dojo”. This means that the person that implemented a new technology or method will educate the team about that technology.
I am not talking about a half-assed poorly prepared 10 minute lecture. No, really getting into the code and explaining the architecture and different part is crucial
Clear documentation on running/testing/deploying
You often start a new repository for your new shiny React application but a lot of the knowledge remains stuck in your shell history.
Creating a clear README from the start on how you run/test and deploy the project will make the other team-members want to try it out and run it locally without the hassle. Think of it as on-boarding a new user on your website, the process should be as smooth as possible.
Summing up
Following some of these steps/tips will allow for a smoother transition to this new architecture/framework.
I really enjoy working with React on this new project and it really allows a lot more flexibility from what we had before.
I am seeing engineers on-board really smoothly into the project because the structure makes a lot of sense and once the uni directional flow clicks in your brain development is really fast and productive
Image credits:
https://medium.com/google-developer-experts/angular-2-introduction-to-redux-1cf18af27e6e#.h8uls08nj