The Redux ecosystem
Or packages you should know to create a Redux production application
Warning: This article is about front-end applications and nothing about server rendering.
What's going on?
Redux & React are currently mainstream technologies in front-end. Every self-respecting front-end developer knows this fact and tries to dive into them to understand what they are and how to deal with them. Because it seems really clear that the future web applications are all about this sweet couple.
The problem is that the process of changing developer's mind to start thinking in React & Redux way isn't actually smooth. Frameworks we used to apply (Backbone, Angular, jQuery, etc.) work in drastically another way, so we need some time to switch.
Obviously, when we hear about React & Redux bunch, we begin to puzzle out exactly those two words. And that's right for a start. React serves as the view layer, Redux serves as the data one...
" Okay, I got it, - you said, - React builds my interfaces using components, Redux handles my data using the singleton data store, actions and reducer functions. Now that's pretty clear for me and it seems like I can develop the whole new application based on it. I don't have anything to worry about. "
Yes, you have!
The truth is that interface building and data handling are not enough to create a real production application. To create a small example like a TODO-list or something - yes. Not for something bigger.
So, the gist is the following. Let's take a look at most of the features that you'll have to deal with when the time comes, - and where React & Redux themselves can't help you. Because the devil is in the details.
First of all, when you develop a big application with React, you need to reuse your components. There's no way just to pass the Redux Dispatcher through the hierarchy of components to give access all of them to throw actions. You need just a small set of components that know what your application does in particular, i.e. what actions it has to change the State and what the State represents exactly. Rid most of them of that and let them do just a dumb work - display the data and handle parents' callbacks. That's how you'll make them reusable.
Talking in terms of Redux those components are smart and dumb or container and presentational. You could (no, you actually must!) read about it here.
When you are aware of this idea, you need a tool to apply it. So, I am pleased to present you react-redux. This package allows you to wrap up a component with a container that provides access to the Dispatcher and the Store, and keeps the wrapped component synchronized with Store mutations. In another words, it makes a component smart.
It represents the high-order component pattern - the approach that suggests you to take an existing component and pass it to a special function that wraps it up in a new one. This wrapper extends the initial component functionality in some way, and you get the profit.
Technically, mixins provided the same opportunity (if you are familiar with them), but they had a bunch of problems, so the React Team decided to cut it off in favor of composition described above. Read more on that topic in this article.
The Provider component that you should put in the root of the hierarchy completes this workflow. It makes the Store available to the components wrapped with the connect method, and works through React's " context " feature.
Context is an advanced and experimental feature, and perhaps you will never need to use it on your own. Anyway, if you want to be aware of it, check out the documentation.
If you have more than one page in your application, you need to define what components correspond to URL paths and what URL paths are available. That's what we call routing. Every front-end framework has the router, - the special part which is responsible for routing.
React is not an exception. However, unlike some other frameworks it doesn't have an integrated router. Instead, you need to use the react-router package that provides this functionality. Moreover, it doesn't work the usual way, but if you've already understood how to work with React, getting used to it won't take much time.
React-router allows you to describe the routes in the declarative way. Every route is just another React component like the Router itself. Pretty clear.
Routing data in the State
Cool, now you have the routing in your application. Yet if you know one of the best advantages of Redux architecture, you can ask why can't you do the time travelling with pages switching like you do with everything else? Why doesn't React Router navigate between pages when you replay actions?
Because Redux and react-router are different libraries and they don't coordinate at all. So let's connect them to each other! That's exactly what the next package does.
React-router-redux (oh, I like this kind of naming so much!) helps you keep the part of the State in sync with your Redux Store. When you rewind your application State with a tool like Redux DevTools, that State change is propagated to React Router so it can adjust the component tree accordingly.
To understand how it works, you need to know that Redux supportsthe great feature called middleware. It provides a third-party extension point between dispatching an action, and the moment it reaches the reducer called. It's very useful and can be used for a variety of things (read about it here). One of these things is what we're talking about. You just need to apply the react-redux-router middleware to your Store to get things done.
There's no real application without authentication. And when you already have routing in yours, authentication represents the rule about how to check if a user is authenticated and what pages he can see depending on it.
Using Redux you obviously should have the data about user authentication in Store. It can be the prop named "user" with the user object (or empty if user's not authenticated) or something like this.
After you add this in your code, you need the tool that helps you mark routes in Router accessible or not. That's what redux-auth-wrapper is for. It's also based on high-order component pattern. You've already seen the example in the react-redux connect method.
A real application works with data through asynchronous requests to API; this means you need to know how to make Redux support async actions. And that's pretty simple if you already know about Redux middleware.
There's one more package that's just a middleware that provides an opportunity to organize async actions flow. It's called redux-thunk. This middleware allows you to pass to the Dispatcher action functions instead of action objects. If you need just a sync action, you should make this function return an action object. But if you need to handle some async stuff instead, you should do it and then dispatch another result actions with the Dispatcher that you have access to through one of the arguments.
For example, if you work with API, you should dispatch an action function that makes the request and dispatch another two action functions in cases when the request is successfully completed or ends with an error. These two action functions is equal to usual sync actions, so it should be handled by the Reducer and change the application State.
This was my attempt to introduce you several of the most important packages that extend the React & Redux functionality to make it possible to create a real application ready for production. If you're a newbie in React & Redux architecture, but you already understand the main principles of those frameworks, this article should introduce you the best practices and patterns, that usually used in with this couple.
Now you know how to (step by step):
- Connect Redux to React and make components more reusable;
- Organize the routing;
- Play with the routing data in Redux DevTools;
- Organize authentication;
- Organize the async flow to work with remote API.
Of course, that's not all that you'd need while developing your application. There are plenty of another packages that work with React & Redux, based on high-order components or middleware or another patterns (see react-dnd - the library for drag&drop, for example). It's obviously clear because React & Redux are main players on the front-end arena now, and it's actually cool that we have such a big choice. But the things described above would help you create the boilerplate that already works, so you can pass it and get more concentrated on distinguishing features of your application.
UPDATED 05.12.2016: Corrected the react-redux Provider component explanation.