6 Lessons Learned From Going To Production With React-Redux
A few months ago I published a blog about how we started to move from Backbone + RequireJS + Handlebars + Grunt to React + Redux + ES2015 and WebPack. Back then, when everything was new to me, I didn’t really understand the challenges and the complexity of things so I did it nice and easy, that’s why the post is call “baby-steps.”
Recently, we wanted to deploy our first full blown React feature to production meaning it had 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 overcame, what we learned during the development, and some of our decisions that we made, both good or bad.
(Above) The final result of our React Redux project.
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 logic, I mean you gotta have some CRUD requests somewhere right? If it’s 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 allowed 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 purchase Tickets 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 wanted 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 like you see below.
(Above) Reducers based on Redux Dev-tools
You can find reducers based on data structures such as: account, event, tickets, order, query etc.
For example: the tickets Reducer 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 and referenced them as Container and Components. For us, a Container is 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 a bit deeper into the technical stuff, a container enhances itself with the high order component Connect, from the react-redux module, and passes the data as props and behaviour methods to the child components.
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 right 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 its only visual state that has no actual effect 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 to doing this, 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 it’s 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: try to implement what is exactly needed in your feature, I know it’s tempting to re-write the wrapping components 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 with the React-Redux-Webpack stack has been great, I believe that we’ve written simpler, more manageable, and more testable code, since the whole app is like one big machine.
Want to join me in as the Bizzabo dev team works with the latest and greatest technologies? Click the button below to apply!