I have seen people stumble and have a lot of trouble trying to get React components to behave correctly because they are trying to force a round peg into a square hole, and program their React components like you would program directly on the DOM with JavaScript and event handlers.
Unidirectional data flow is a core concept in React, and understanding it is key in order to create working React applications. Unidirectional data flow is the essence of React.
I recommend that you make sure you follow this closely and really understand Unidirectional Data Flow. This way when you code your React applications, you will be much more confident in getting them working flawlessly.
What is Undirectional Data Flow?
Unidirectional data flow means "data flowing in one direction".
The diagram below shows this flow, and I will explain it a bit more below, both as a general concept, and then talk about how it applies to React.
State
In the diagram above we start with State. State is the data that drives what you see in the user interface. It is concerned with the "facts", for example there are 3 invoices, the first is for $100, the second for $150, etc.
The state is not directly concerned about how things look (that job is left to the view).
The state doesn’t have to contain all of the information about what is happening in the app, although it can if you want. At a minimum it needs to store what is required for the view.
What you choose to put in state (or not) is a bit of an art and science that will become more intuitive with experience.
As a rule of thumb, if you can calculate it from other state, leave it out. Instead, let your view calculate that value each time. For example the total amount of the 3 invoices above does not need to be in state because you can work that out from the invoices themselves.
View
The view is where the state is converted into the user interface.
The app developer writes a function that given the current state, returns the desired user interface definition. You could think of this as a function that takes the state and returns HTML.
For example your state might have an array of invoices
[
{ amount: 100, name: 'John' }
]
The view could convert each invoice to some HTML like <li>John - $100</li>
and wrap these in a <ul>
tag:
<ul>
<li>John - $100</li>
</ul>
Of course in general HTML doesn’t have to be used as the "mark up" language for unidirectional data flow. In React for example, React Components are used, and these can be written in the convenient JSX language which is similar in appearance to HTML.
Events
Events are what allow interactivity with this user interface. Otherwise your app is just a movie!
The setting up of events, e.g. "when you click this button, call this code" is actually done by the view, because the view is where the button is defined in the first place.
The code that is called when the events happen can then do whatever needs to be done – make a network request for example.
One thing they cannot do is update the user interface! Well not directly anyway. If they want to update the user interface, they need to update the state. This in turn will update the user interface.
Why go to all this trouble?
Having explained all of this, I feel it sounds complex if all you want to do is build a web app. Why not just use JavaScript’s event handlers and document.getElementById
etc.?
The advantage of the unidirectional data flow is having one source of truth for your user interface.
With plain JavaScript, there isn’t one part of your code responsible for the user interface. Any event handler can go and update any part of the app. For small apps this might be OK, but as apps get bigger this leads to chaos and a lot of bugs, unless the developer(s) are very disciplined.
Another advantage of unidirection data flow is you can update the view, in fairly drastic ways, without having to touch the state or business logic of the app. This means fairly big redesigns of your component are possible without too much fuss or risk of introducing bugs.
With plain Javascript on the other hand, you might need to assume that elements are siblings or parents in your code, and then when you rearrange the user interface, various parts of the code might break.
In short, unidirectional data flow reduces bugs in larger applications.
Unidirection Data Flows with React
If you were to use the undirectional data flow pattern with plain JavaScript, you would need to write a few utilities to help you do the following:
- Manage the State: Know when the state is updated, call the view function when needed.
- Update the DOM: Apply the results of the view function to the DOM (Document Object Model – the web browser’s programming interface for updating the user interface).
- Events: Make sure that events are created in the DOM and call the right code, remove old events that are no longer needed.
Luckily we have a library to do all of this and more: React!
In part 2 of this post (coming soon!) I will talk a bit more about where in React these concepts apply, both for function components using the modern hooks approach, and the "older" class components approach.
If you want to know when Part 2 is ready, sign up below and I will keep you up to date.