What's Redux?
Redux is a predictable state management library designed to help you write JavaScript apps that behave consistently across client, server, and native environments and are easy to test.
Why should you think about using Redux?
According to Redux official docs:
"Redux helps you manage "global" state - state that is needed across many parts of your application.
The patterns and tools provided by Redux make it easier to understand when, where, why, and how the state in your application is being updated, and how your application logic will behave when those changes occur. Redux guides you towards writing code that is predictable and testable, which helps give you confidence that your application will work as expected."
What is the problem Redux trying to solve?
The problem Redux wanted to solve is predictable state updates as knowing where and why the state changes and having a "single source of truth" can be an advantage.
Redux allows you to debug the application easily, how?
by separating the UI layer away from the data, that helps you to be able to understand what is going with the application at all times.
What are Redux main principles?
We can summarize the intent behind Redux's design in three core concepts:
1.Single Source of Truth
Everything that changes in the app (data, UI)state is contained in a single object (*state tree/store *)
The initial state of the store is up to you but it's typically an Object -like a model- and it doesn't need a setter in order to set it initially.
Store:
An object that holds the whole state tree of the app, it has a few methods on it:
getState()
dispatch(action)
subscribe(listener)
-
replaceReducer(nextReducer)
We will talk more about the store and its methods in later on.
How to create your redux store?
Pass your root reducer function to createStore, like this:
const userReducer = function(state = [], action) {
if (action.type === 'ADD_USER') {
var newState = state.concat([action.user]);
return newState;
}
return state;
}
const store = createStore(users, ['Use Redux'])
store.dispatch({
type: 'ADD_USER',
user: {name: 'Rawan', language: 'EN'}
})
createStore(reducer, [preloadedState], [enhancer])
We would only now talk about the "preloadedState" and we would explain the reducer later on.
[preloadedState]: the application's initial state.
2.State is read-only
State-Tree is read-only and the only way to change the state (send data from your application to your Redux store) is to dispatch an action, like this:
const action = {
type: 'ADD_USER',
user: {name: 'Rawan', language: 'EN'}
};
store.dispatch(action);
What does it mean to dispatch an action?
You can think of dispatching actions as "triggering an event" in the application. Something happened, and we want the store to know about it.
Action:
Is a plain JS object describing the change, with a type field to indicate the type of action to be performed.
The type field should be a descriptive string, in the format of "domain/eventName" like " users/userLogin".
An action object can have other fields with additional information about what happened. We call that a "payload".
const userLoginAction = {
type: 'users/USER_LOGIN',
payload: {
username: "Adam",
password: "pass1234"
}
}
As you can see we declared the action as an object that has a type and payload.
3.Changes are made with pure functions (Reducers)
To specify how the state tree is transformed by dispatched action, we write pure functions called Reducers to do so.
Pure function:
Is a function which, given the same input, will always return the same output (state) and Its return value depends solely on the values of its parameters.
for example: If you pass 1 and 4 to a summation function, youβll always get 5.
Also, the pure function should have no side-effects like:
Mutating your input, Network calls, Changing the filesystem (fs), Querying the DOM, Setting an async timer, Modifying some state that exists outside of a function, or mutating arguments to a function, generating random numbers or unique random IDs (such as Math.random() or Date.now()) ...etc
Reducer:
A reducer takes in the current state and an action object as arguments and can only modify the state by returning a new state.
and as redux docs state:
You can think of a reducer as an event listener that handles events based on the received action (event) type.
Reducers have 3 important rules:
- Should only calculate the new state value based on the state and action arguments.
- They are not allowed to modify the existing state.
- They can only make immutable updates, by copying the existing state and making changes to the copied values. They must not do any asynchronous logic, calculate random values, or cause other "side effects".
As you can see, the rules of reducer match those of a pure function, but why should we follow these rules?
Code predictability, when a function's output is only calculated from the input arguments, it's easier to understand how that code works and to test it.
If a function modifies other values, including its arguments(( the current state, action )), that can change the way the application works unexpectedly. This can be a common source of bugs, such as "I updated my state, but now my UI isn't updating when it should!"
Some of the Redux DevTools capabilities depend on having your reducers follow these rules correctly.
In Conclusion,
Redux stores all the app state in one place which is a single source of truth called "store", in order to change the state, components can "dispatch" an action to change the store change, then the components that need to be aware of state changes can βsubscribeβ to the store to get the state change, as shown:
Finally, here's a brief summary of what happens using redux:
That's it for this article, this is just an intro to redux main concepts, I hope you learned something :)
Happy Coding!
Resources:
https://redux.js.org/
Top comments (4)
Great article, thanks
Great article but my question is, while obviously it is still relevant, is it still the right choice in 2022 while we already have great alternatives like zustand that greatly reduce the boilerplate at no compromises?
dev.to/reactjs/redux-best-practice...
Impressive! thank you for sharing such a good article.