In this tutorial we look at the concepts behind the Flux pattern for building user interfaces.
In this lesson we're going to look at the Flux pattern for building user interfaces.
We'll first look at the main concepts behind Flux, and then we'll see how to use it with the Redux library.
Flux is a pattern for managing data flow in user interfaces.
It was developed by Facebook.
Flux itself is not a framework; it's just a set of ideas, but there are frameworks based on the ideas of Flux, like Redux and MobX.
Fundamentally, Flux is a pattern for managing data flow in your application. It's an alternative to using a client-side MVC framework.
A key principle of Flux is that data flows in one direction.
Now, why do we need Flux? We need it to make our data and state management easier.
For example, one of the early applications of Flux, at Facebook, was keeping chat message notifications in sync.
In React apps, Flux solves the problem of passing state down the component hierarchy.
Instead, any component can directly connect to a data store in Flux and get the data it needs. Flux has 4 parts.
A dispatcher, data stores, actions, and views.
This diagram shows the flow of data between these four parts.
A view emits actions, say, in response to a user input, which is sent to a dispatcher, which then sends the action to stores.
Stores are where all the app data is stored.
The store then decides what to do with the action, and how to change the app data in response to that action.
Once it's done that, the store emits a change event, and views listen for these change events by subscribing to stores.
When a view receives new data from a store, it passes it to any child views, and they get re-rendered.
Apart from user input, you can also get actions from other sources, like, say, an external API.
Notice here the data between any two parts is only moving in one direction.
This is a key difference from MVC.
So the flow of data goes like this:
Views send actions to the dispatcher.
The dispatcher sends actions to every store, and stores send modified data to the views, which then re-render.
Now let's look at each of these four parts in some more detail.
First, the dispatcher.
It receives actions from views, and other sources like servers, so whenever a user interacts with the app, say, by submitting a form, the dispatcher will get an action from that view.
And then the dispatcher dispatches them, to stores that have registered with the dispatcher.
Every store will receive every action.
So that's what the dispatcher's doing.
Handling action from views, and sending them to stores.
It acts like a traffic controller.
It ensures that until your stores are done, processing the previous action, new actions can't be inserted.
Then, we have stores.
Stores hold the data, or state, of an application.
In a React app without Flux or Redux, we manage the state inside components themselves.
When we use Flux, we manage that state in Flux stores.
Stores register with the application dispatcher, so that they can receive actions.
And then, when a store receives an action, it uses that action to mutate the data based on the type of action.
The data in the store must only be mutated by responding to an action.
And each store can decide what actions it wants to respond to.
Every time a store's data changes, it must emit a change event, which the views subscribe to, so they can re-render.
A Flex app can have multiple stores.
But in Redux we only have one single store, as we'll see in the next lessons.
Actions define the internal API of your application, the business logic of your app.
For example, in our calendar app, actions are changing the input title, setting the appointment time, and submitting the form to create an appointment, and also, deleting an appointment.
So actions capture the ways in which anything might interact with your application.
They are simple objects that have a type field and some data.
Finally, we have views, which is what we've been building in our example app with React.
That's where data from stores is displayed.
When a view uses data from a store, it also needs to subscribe to change events from that store.
Then, when the store emits a change, the view can get the new data and re-render.
Actions are typically dispatched from views, as the user interacts with parts of the application's interface.
So, to recap, this is the uni-directional flow of data in a Flux app.
A view emits an action, a dispatcher receives that action, and it sends it to a store.
Once the store has mutated the data based on the action, it emits a change event to the view, which then re-renders.
The store doesn't send the data back to the dispatcher, and the dispatcher doesn't send it back to the view.
It just goes in this one direction.
Now I wanna briefly touch on a pattern in React, which relates to Flux.
It's the idea of container, or smart components, versus presentation components.
Container components are components that handle app logic, and presentational components are simple function components, which only display data.
We've used them in our app already.
So, for example, our first simple appointment component was a presentational component and our appointments component is a smart component, where we manage state.
In the context of Flux, container components are the views that subscribe to the data store, and emit actions to the dispatcher.
Presentational components, on the other hand, just receive data as props, and return a bit of UI to display that data.
They don't handle any business logic.
Structuring your app in this way, by separating components into container and presentational components, is a good pattern for re-using code, tests, and for easily making changes.
Now sometimes you might find that a component has a mix of presentation and logic and it's not quite clear whether you should make it one type or the other.
But that's ok.
As long as a component is small, it doesn't matter so much.
This is just a pattern to make life easy.
It's not a hard and fast rule.
I'm mentioning this because sometimes people get caught up in this, and act as if it's a rule that must not be broken.
But it's just a pattern to make your code re-usable, and easier to test and change.