Once upon a time, there was a kingdom that was getting the king's message(s) from his messenger(s). Now, hold this analogy and come back to the world of web development where the king is the parent component and the message is the shared state by all the responsible children components.
While Facebook was growing as a product and as a company, two major things will increase i.e. traffic & business which will require them to add more features and lesser bugs to the product. Hence they introduced not just the chat part but also its 3 major visibility too
Now all three domains highlighted above will show the state of the chat counts that are read or unread. Now the more features were getting added up the more code complexity was increasing and the chances of a buggy interface increased.
MVC architecture
Now all the problems at that time had their root cause at the meshy structure due to MVC so we needed a better solution that will make my consumer components or children components have a continuous subscription to the state changes from any source of truth. And that lets us have an architecture where there will be the usage of Node's event listener on our UI component(View) so that when there is any sort of actions on UI that respective action will be dispatched and eventually all the actions will get listened across multiple stores.
Just for visualization one may consider Flux is nothing but an evolved MVC where : View - remains the same Model - actions + dispatchers (multiple actions with their respective dispatchers) Controller- stores (multiple stores listening to all events)
Although the stores are listening to all the events regardless of that, it will mutate only the specific state according to the action type.
FLUX architecture
Advantages of the FLUX architecture:
- Unidirectional data flow i.e. the direction of flow of information through the dispatcher to the view
- Simple & scalable code
- Better chances of Unit testing
Although Flux has lifted the state to one global store that will be a single source of truth for all the concerned components hence the problem of maintaining consistency is resolved but some major issues were identified later.
Problems with the FLUX architecture:
- Flattened structure of state objects
- The user needs to remember the store structure as here it's created via instantiated class
- Unable to support the SSR due to its implementation based on Singelton Pattern
- Unit testing has been made possible but multiple stages of state mutation make it difficult
Now, considering above mentioned pros & cons w.r.t. Flux architecture it is visible that there is a fair amount of improvements that can be integrated into it or can we replace it completely? Hence, that led to the birth of a new prince in the kingdom & whom people called Redux.
Note: Flux was introduced as a concept but later on with community support there was the introduction of many 3rd party dependencies to enhance itself and that led to providing even Flux as a dependency on NPM. You can find it here.
Click here to get the codebase for Flux
Redux library
As indicated in the above diagram, one can see that now there are 2 major constituents in the architecture:
- Single store unlike multiple stores in Flux
- Multiple reducers
If we consider the above-mentioned drawbacks of Flux architecture then we can easily overcome them using the most popular 3rd party support to Flux, which is called Redux.
Following are the definitions that can be put into consideration while talking about the redux:
Redux:- A predictable state container for Javascript applications
Store:- A storage that holds a global state in the form of an object tree
Actions:- A pure function that returns an object having action type & payload
Reducers:- A pure function that returns an object having updated state after consuming 2 params- state & action
A point that can be noticed while implementing the redux is that it gives one big state object in store which doesn’t get mutated but we abide by the object’s im-mutability characteristics and we create a new object every time some action is called by any event.
Deep dive into redux:
1) Remembering store structure:
The critical advantage of Redux over Flux is that in Flux we need to have knowledge of states in all the stores whereas in Redux we have only ONE store hence, we don't have to be concerned about maintaining conditions again and again
2) Reducer Composition:
Flux has a flat structure whereas redux has a hierarchical structure, what I mean is Flux uses callback registration whereas redux has a functional composition structure the same as any component in react. Therefore if we need to mutate the same state with 2 different actions then it becomes much easier in Redux. e.g :
- Pagination with next & prev button
- Undo/Redo operation
3) Server-side rendering:
Core flux work on a singleton pattern, therefore if any action is getting dispatched then the store change persists, which is exactly what we DO NOT need for SSR.
Because class-based stores are hard to be created and destructured & it's hard to even hydrate data from store to client.
Using some 3rd party assistance we can do it but that’s relatively complicated as to that of Redux because redux has only ONE big store object, and it's easy to play along with the store.
4) Developer's experience: With flux, it's not hard but impossible to time-travel the store state, and that too with hot-reloading (hot reloading is reloading which doesn’t cause state loss). Redux gives that independence only because the Redux base relies on state immutability using the spread operator (...) or 3rd party dependency like Emmer. js.
We can do so with Redux because of the in-built replaceReducer() hook.
Quick recap:
Note: Redux is not coupled with React hence we can use it even with simple HTML and JS too as shown below:
End notes on redux
Redux requires a fixed boilerplate amount of code instead of being a one-liner change and that boilerplate is based on a pattern that the Redux team calls as DUCKS pattern & the evolved version of redux i.e. @reduxjs/toolkit a.k.a RTK.
Redux-js Toolkit or RTK can also be considered a one-stop solution for making global state management, asynchronous IO calls, state immutability, caching on the server side.
Middleware in Redux
Middleware in redux can be considered an add-on that will be applied to the action and can be used to do any extra operations like IO calls, logging any message, etc. That can be visualized in the following diagram.
The sandbox below demos middleware usage