While React.js provides stateful components, managing state across entire single-page-applications requires an isomorphic tool. More specifically, we need a single source of truth. Managing state in a declarative framework like React.js is critical and easy to get wrong. How can we minimize side effects, while maximizing testability and reproducibility? We separate data, logic, and rendering. How can we visualize the changes we are pushing to our state? We use uni-directional data flow to easily reason about the interactions between actors.
Redux is a tiny (2kb) library used most commonly with React.js single-page-applications to manage its state. It has an excellent browser dev tool that shows the actions you make, and the state mutations that are caused by them.
Redux uses a single source of truth, called "the store", which is an immutable object tree. The only way to change the data is emitting "actions", which describe what you want to do. These actions use "reducers" to perform the mutations to the state. Since these concepts are rooted in functional programming, the code is highly unit testable.
Function | React With react-redux |
Server |
---|---|---|
Presentation View | React Components |
Client API |
Communication | Action |
Function Invocation |
Logic to massage data for Storage | Saga |
Services |
Data Storage | Store |
Database |
Our TELUS isomorphic starter kit defines our standard UI application, with React and Redux at its heart. The FAQ has a lot of information about how we use Redux.
- Responsible for presentation and user interactions.
- Blind to the complexities of the app since it does not know what happens after the action is broadcasted.
- Able to react to state change via
connect
.
- Responsible for communication between parts of redux
- Use event description instead of function invocation
- Listeners determine how to react to actions
-
Describe an event via actions
-
Actions describe a need as a fact or an event already happened, without dictating how to fulfill the need.
Eg. Need =>
TIME_TO_TRAVEL_ARRIVED
personOneSaga
reacts by =>startWalking()
personTwoSaga
reacts by =>callTaxi()
- Responsible for application state (immutability, persisting to disk, etc).
- The Single Source of Truth.
- Keeper of state information, should not keep business logic.
- Can only be affected by actions.
- Prevents unintentional modifications by other methods via object reference, or directly accessing store members.
//Reducer
export const people = (state = [], action) => {
switch (action.type) {
case 'PERSON_REMOVED':
return state.filter(person => person.id !== action.payload);
default:
return state;
}
};
- Responsible for business logic and asynchronous actions (HTTP Calls).
- Does not keep local state.
- Typical use is take user input, make an HTTP call, and provide output to go into the store.
Front-end developers