Redux
What is Redux?
- Redux is an open-source JavaScript library for managing application state
- Commonly used with libraries such as React or Angular for building user interfaces.
- Similar to (and inspired by) Facebook's Flux architecture, it was created by Dan Abramov and Andrew Clark.
What is State?
- State: the particular condition that something is in at a specific time.
- Application State (also known as Program State)
- Represents the totality of everything necessary to keep your application running
- The state of the program/application as it exists in the contents of its memory
- In any given point in time, there is a different information stored in the memory of your web application
- Can be accessed via your variables, classes, data structures, etc.
- All the stored information, at a given instant in time, is called the application state
- Examples of Application State
- The current URL of a web page
- The displayed data often returned from a call to a web API using HTTP
- How the data is currently sorted or filtered
- Whether a user is logged in and their associated profile data
- Whether a navigation menu is currently open and displayed or hidden
- What to Store in State?
- Shared data
- Does the data matter to the application as a whole?
- Are there other components that may benefit from this global accessible shared data?
- Shared data
Benefits
- Predictable state updates make it easier to understand how the data flow works in the application
- The use of "pure" reducer functions makes logic easier to test, and enables useful features like "time-travel debugging".
- Centralizing the state makes it easier to implement things like logging changes to the data, or persisting data between page refreshes
Benefit Checklist
- Explicit state, predictable state, repeatable trail of state
- Performance
- Testability
- Debugging/Tooling
- Time travel debugging
- Record/Replay
- Hot reloading
- Refreshes files that were changed without losing the state of the app
- Component Communication
"Redux is not great for making simple things quickly. It's great for making really hard things simple." - Jani Evakallio
When do you need Redux?
- Persist state to a local storage on the client and then boot up from it, out of the box.
- Pre-fill state on the server, send it to the client in HTML, and boot up from it, out of the box.
- Serialize user actions and attach them, together with a state snapshot, to automated bug reports, so that the product developers can replay them to reproduce the errors.
- Pass action objects over the network to implement collaborative environments without dramatic changes to how the code is written.
- Maintain an undo history or implement optimistic mutations without dramatic changes to how the code is written.
- Travel between the state history in development, and re-evaluate the current state from the action history when the code changes, a la TDD.
- Provide full inspection and control capabilities to the development tooling so that product developers can build custom tools for their apps.
- Provide alternative UIs while reusing most of the business logic.
Principles of Redux
- Single source of truth
- The whole state of your app is stored in an object tree inside a single store.
- Describe application state as plain objects and arrays.
- State is read-only
- The only way to change the state tree is to emit an action, an object describing what happened
- Describe changes in the system as plain objects.
- Changes are made with pure functions
- To specify how the actions transform the state tree, you write pure reducers.
- You describe the logic for handling changes as pure functionsfunction reducer(state = initialState, action) {switch (action.type) {case 'LOAD_PHOTOS_REQUEST':return { ...state, processing: true };case 'LOAD_PHOTOS_SUCCESS':return { ...state, processing: false, photos: action.payload };case 'LOAD_PHOTOS_FAILURE':return { ...state, processing: false, error: action.payload.message };default:return state;}}
Core Concepts
State
- The application data
- as it exists in the contents of its memory
- We define
- the shape of the data
- initial values
- State is held by the Storelet appState = {todos: [{ text: 'Consider using Redux', completed: true },{ text: 'Keep all state in a single tree', completed: false },],visibilityFilter: 'SHOW_ALL',};
Actions
Actions
- a custom event (action) that is raised (dispatched)
- an plain JavaScript object with a
type
property - other than
type
, the structure of an action object is really up to you - typically there is one other property
payload
where other information is passed
Action Types
- types should typically be defined as string constants
- action type names take the form of
- VERBENTITY[ REQUEST | SUCCESS | FAILURE | ]
- Examples:
- LOAD_PHOTOS_REQUEST
- LOAD_PHOTOS_SUCCESS
- LOAD_PHOTOS_FAILURE
Action Creators
- functions that create actions
- makes them portable and easier to test
- useful when doing async
Reducer
- a function
- takes two parameters:
state
andaction
- returns a new state
- takes two parameters:
- typically just a switch statement
- immutable
- so the debugging features work correctly
- always set the default state
- handled in the
default
case of the switch statement
- handled in the
- when you want to split your data handling logic, you'll create multiple reducers and compose them into one higher level reducer
Store
- the
Store
is the object that enables the other concepts to work together - the
Store
has the following responsibilities:- Holds application state
- Allows access to state via
getState()
- Allows state to be updated via
dispatch(action)
- Registers listeners via
subscribe(listener)
- Handles unregistering of listeners via the function returned by
subscribe(listener)
Developer Tools
Enables a richer debugging experience including:
- logging
- time travel
utilize browser debugging tools that understand redux and enable time-travel debugging and hot-reloading
Redux DevTools can be extremely helpful as the number of HTTP calls for a given screen grows and it becomes necessary to coordinate the order in which those calls return.
Complementary Packages
Redux by itself is often not enough to build a real application. You will need to use complementary packages to:
- have async actions...actions that make AJAX/http calls (Redux Thunk)
- easily use the library with React without unnecessarily coupling the libraries (React Redux)
The next few chapters provide more detail on each of these commonly used complementary packages.
Demos
Counter Demo
- Install
- Add scripts
- Add the following code to
main.js
- If your web server is not running, start it up:
- Open
http://localhost:5000/
in your browser - You should see the following output
Debugging & Time Traveling Demo
- Install the Redux DevTools Extension in Chrome by following these directions
- Configure your store to use the extension
- Open the Chrome DevTools
- Click on the Redux Tab
In a Create React App you would:
npm install --save-dev redux-devtools-extension
Then configure your store to use the extension by following these directions
Gotchas/Tips
- In practice, the reducer and the state property that is computed by the reducer have the same name
Reference
Redux
- Documentation
- Redux creator Dan Abramov's free "Getting Started with Redux" video series
- Examples
- You Might Not Need Redux
Action Creators:
DevTools
Configuring devtools & thunk
- Advanced Store Setup
- Configuring Redux Devtools using UMD Build
- Problems with this Approach to Configuring Your Store
Repositories