Redux
Redux is a pattern and library for managing and updating application state, using events called actions. It serves as a centralized store for state that needs to be used across the entire application, with rules ensuring that the state can only be updated in a predictable fashion.
Actions, Store, Immutability & Reducers
Actions & Action Creators
An Action is a plain JavaScript object that has a type
field. An action object can have other fields with additional information about what happened.
By convention, that information is stored in a field called payload
.
Action Creators are functions that create and return action objects.
JavaScript | |
---|---|
Store
The current Redux application state lives in an object called the store.
The store is created by passing in a reducer, and has a method called getState
that returns the current state value.
The Redux store has a method called dispatch
. The only way to update the state is to call store.dispatch()
and pass in an action object.
The store will run its reducer function and save the new state value inside.
Selectors are functions that know how to extract specific pieces of information from a store state value.
In initialState.js
;
In configStore.js
:
Reducers
Reducers are functions that receives the current state and an action, decide how to update the state if necessary, and return the new state.
Reducers must always follow some specific rules:
- They should only calculate the new state value based on the
state
andaction
arguments - They are not allowed to modify the existing
state
. Instead, they must make immutable updates, by copying the existingstate
and making changes to the copied values. - They must not do any asynchronous logic, calculate random values, or cause other "side effects"
Note: multiple reducers can be triggered by the same action since each one operates on a different portion of the state.
React-Redux
Container vs Presentational Components
Container Components:
- Focus on how thing work
- Aware of Redux
- Subscribe to Redux State
- Dispatch Redux actions
Presentational Components:
- Focus on how things look
- Unaware of Redux
- Read data from props
- Invoke callbacks on props
Provider Component & Connect
Used at the root component and wraps all the application.
Async Operations with Redux-Thunk
Note: Redux middleware runs after and action and before it's reducer.
Redux-Thunk allows to return functions instead of objects from action creators.
A "thunk" is a function that wraps an expression to delay it's evaluation.
In configStore.js
:
Redux-Toolkit
The Redux Toolkit package is intended to be the standard way to write Redux logic. It was originally created to help address three common concerns about Redux.
Redux Toolkit also includes a powerful data fetching and caching capability dubbed "RTK Query". It's included in the package as a separate set of entry points. It's optional, but can eliminate the need to hand-write data fetching logic yourself.
These tools should be beneficial to all Redux users. Whether you're a brand new Redux user setting up your first project, or an experienced user who wants to simplify an existing application, Redux Toolkit can help you make your Redux code better. Installation Using Create React App
The recommended way to start new apps with React and Redux is by using the official Redux+JS template or Redux+TS template for Create React App, which takes advantage of Redux Toolkit and React Redux's integration with React components.
Bash | |
---|---|
Redux Toolkit includes these APIs:
-
configureStore()
: wrapscreateStore
to provide simplified configuration options and good defaults.
It can automatically combines slice reducers, adds whatever Redux middleware supplied, includes redux-thunk by default, and enables use of the Redux DevTools Extension. -
createReducer()
: that lets you supply a lookup table of action types to case reducer functions, rather than writing switch statements. In addition, it automatically uses theimmer
library to let you write simpler immutable updates with normal mutative code, likestate.todos[3].completed = true
. -
createAction()
: generates an action creator function for the given action type string. The function itself hastoString()
defined, so that it can be used in place of the type constant. createSlice()
: accepts an object of reducer functions, a slice name, and an initial state value, and automatically generates a slice reducer with corresponding action creators and action types.createAsyncThunk
: accepts an action type string and a function that returns a promise, and generates a thunk that dispatches pending/fulfilled/rejected action types based on that promisecreateEntityAdapter
: generates a set of reusable reducers and selectors to manage normalized data in the store- The
createSelector
utility from the Reselect library, re-exported for ease of use.
configureStore
Included Default Middleware:
-
Immutability check middleware: deeply compares state values for mutations. It can detect mutations in reducers during a dispatch, and also mutations that occur between dispatches. When a mutation is detected, it will throw an error and indicate the key path for where the mutated value was detected in the state tree. (Forked from
redux-immutable-state-invariant
.) -
Serializability check middleware: a custom middleware created specifically for use in Redux Toolkit Similar in concept to
immutable-state-invariant
, but deeply checks the state tree and the actions for non-serializable values such as functions, Promises, Symbols, and other non-plain-JS-data values When a non-serializable value is detected, a console error will be printed with the key path for where the non-serializable value was detected. -
In addition to these development tool middleware, it also adds
redux-thunk
by default, since thunks are the basic recommended side effects middleware for Redux.
Currently, the return value of getDefaultMiddleware()
is:
JavaScript | |
---|---|
createAction
createReducer
createSlice
A function that accepts an initial state, an object of reducer functions, and a "slice name", and automatically generates action creators and action types that correspond to the reducers and state.
Internally, it uses createAction
and createReducer
, so it's possible to use Immer to write "mutating" immutable updates.
Note: action types will have the <slice-name>/<reducer-name>
shape.
createAsyncThunk
The function createAsyncThunk
returns a standard Redux thunk action creator.
The thunk action creator function will have plain action creators for the pending, fulfilled, and rejected cases attached as nested fields.
The payloadCreator
function will be called with two arguments:
arg
: a single value, containing the first parameter that was passed to the thunk action creator when it was dispatched.thunkAPI
: an object containing all of the parameters that are normally passed to a Redux thunk function, as well as additional options:dispatch
: the Redux store dispatch methodgetState
: the Redux store getState methodextra
: the "extra argument" given to the thunk middleware on setup, if availablerequestId
: a unique string ID value that was automatically generated to identify this request sequencesignal
: anAbortController.signal
object that may be used to see if another part of the app logic has marked this request as needing cancellation.- [...]
The logic in the payloadCreator
function may use any of these values as needed to calculate the result.
RTK Query
RTK Query is provided as an optional addon within the @reduxjs/toolkit
package.
It is purpose-built to solve the use case of data fetching and caching, supplying a compact, but powerful toolset to define an API interface layer got the app.
It is intended to simplify common cases for loading data in a web application, eliminating the need to hand-write data fetching & caching logic yourself.
RTK Query is included within the installation of the core Redux Toolkit package. It is available via either of the two entry points below:
C# | |
---|---|
RTK Query includes these APIs:
createApi()
: The core of RTK Query's functionality. It allows to define a set of endpoints describe how to retrieve data from a series of endpoints, including configuration of how to fetch and transform that data.fetchBaseQuery()
: A small wrapper around fetch that aims to simplify requests. Intended as the recommended baseQuery to be used in createApi for the majority of users.<ApiProvider />
: Can be used as a Provider if you do not already have a Redux store.setupListeners()
: A utility used to enable refetchOnMount and refetchOnReconnect behaviors.