A few months ago i published a blog about how we started to move at Bizzabo from Backbone + RequireJS + Handlebars + Grunt to React + Redux + ES2015 + WebPack. Back then, when everything was new to me, i didn’t really understood the challenges and the complexity of things so i did it nice and easy, I called it then “baby-steps”. Now, we wanted to deploy our first fully blown React feature to production, it has to be “production ready”, both in code quality and best practices. There are many things I have learned from my experience but wanted to share the challenges we had, and what we learned during the development and some of our decisions that we made, good or bad, well that’s for you to decide.
#1 — Actions
Actions are payloads of information that you send from your app to your store. Furthermore they are the only source of data for the store. So we found ourselves adding there logic, i mean you gotta have some CRUD requests somewhere right? if its not in the react component and there is no actual data layer that is responsible then someone is, the action.
This caused us to add API calls to the action, which is good because redux-thunk middleware allows you to asynchronously trigger your actions, but if you have several calls to do, parallel or not, the code becomes long and messy. This made us realize we should simplify our actions.
So we decided to use promises, for every action, it will allow us to chain actions in the order we need (or run in parallel) and better control the action, as it only does one thing for one action.
Here is an example of an action:
Notice how the purchaseTickets method returns a promise, this allows us to chain several actions together so we can perform:
purchaseTickets().then(() => myOtherAction())
There is another way to perform CRUD requests inside the Redux flow — middleware. Frankly, if we had more time we would definitely look into this solution also.
#2 — Reducers
Defining how to divide and manage the reducers wasn’t simple for us. Most of the examples and starter kits have very simple reducers with simple logic. We weren’t sure whether we want to define a reducer per page, per feature or based on the data structure. In the end we decided on the latter, After all, our app is Backbone based in its core, and backbone manages the data structures with models and collections, so we modelled our reducers similar.
You can find reducers based on data structures such as: account, event, tickets, order, query etc.
For example: the ticketsReducer holds all the data related to tickets- the tickets themselves, ticket types, fees and more.
Every React component uses several reducers in a real world application, as most advanced apps use several data pieces.
#3 — Smart And Dumb Components
If you have been using React for a bit you might have heard the term “smart and dumb components”, Dan Abramov wrote a great blog explaining the concept. We decided to adopt this concept reference it as Container and Components. For us, a Container is in concerned with how things work, it passes data as props to its children and is in charge of the behaviour of the children. Every container can hold other containers and components.
A Component is just a React component. It is mostly in charge of the view itself and how the view looks. it doesn’t interact directly with the Flux flow, but rather uses the data passed as props to represent the data, and uses methods that were passed by the parent.
If we dig on that a bit deeper into the technical stuff, a container enhances itself with the high order component Connect, from the react-redux module, and pass the data as props and behaviour methods to the child components
This is How we module our application. The Container is usually a page that is related to a feature of some sort.
#4 — Props vs. State
One of the main questions when using React and Redux is do you use state or only use props. Some claim that you should use only props, and some say that you should use props as the data representation and state for UI states of the view. In our application we implemented both, and although i believe that there is more than one answer we decided in the end on the following: the data is the single point of truth and it is only represented using the props, as part of the redux flow. If it’s only visual state that has no actual affect on the data, then we can use the setState() method and manage the state in the view.
#5 — Develop outside your app
Because we integrated React inside an ongoing application with built and tested components, we had to do the same for the React part of the application. We had to write the UI components to look and behave the same as the one we already have using Backbone. We Ended up writing a Kitchen-Sink application. For those who don’t know what “Kitchen Sink” means — The English phrase “Everything but the kitchen sink” means “almost anything one can think of”. For us it means an app that is a showcase of all the React components you can use in the app. There are several advantages, one is that you develop your react components outside of your feature, allowing it to be written more easily and less bound to the features behaviour. It’s also a great way to pass knowledge to other developers as you can add all the options and capabilities of each component if you wish. In other words its like the component’s documentation.
#6 — Connecting the Dots
When we integrated the two frameworks, unfortunately, not everything was easy and smooth, and we had some leftovers of components and services we didn’t have time to implement . So we needed to use several components that are already working and tested from our backbone app to save some time, for example the main menu and the footer of our app, the web-socket listeners, and more. We ended up creating one file, we called it ReactBackboneInit.js. Basically it contains the initialization of the components that we didn’t have time to migrate to react-redux yet. Encapsulating it in one file makes the code more organized, and if you would like one day to convert it to React-Redux it will be easy to find. My tip here, try to implement what is exactly needed in your feature, i know its tempting to re-write the wrapping components also with a new framework, but you can start by leaving it as is and focus on the core issues of your feature.
My overall experience from the React-Redux-Webpack stack has been really great, i believe that you write simpler code, more manageable and its easier to test it, as the whole app is like a one big state-machine.
What did you learn from publishing your react app to production?
we are hiring @ Bizzabo, come join us!