Overview
- Redux uses a "one-way data flow" app structure
- State describes the condition of the app at a point in time, and UI is rendered based on that state
- When something happens in the app:
- The UI dispatches an action
- The store runs the reducers, and the state is updated based on what occurred
- The store notifies the UI that the state has changed
- The UI re-renders based on the new state
- Concepts
- Actions are plain objects with a
typefield, and describe "what happened" in the app - Actions also contain a
payloadthat can be accessed in reducers when calculating new state - Reducers are functions that calculate a new state value based on previous state + an action
(state,action)=>{} - A Redux store runs the root reducer whenever an action is dispatched
- Usage
- Config
- A redux store can be configured via the Redux Toolkit
configureStoreAPI configureStoreaccepts areducerfunction as a named argument- Wrapping the app with
<Provider store={store}>enables all components to use the store - Global state should go in the Redux store, local state should stay in React components
- Slices
- Redux Toolkit's
createSliceAPI generates action creators and action types for each individual reducer function you provide - A "slice" contains the reducer logic and actions related to a specific feature / section of the Redux state
- Reducers
- Should only calculate a new state value based on the
stateandactionarguments - Must make immutable updates by copying the existing state
- Cannot contain any asynchronous logic or other "side effects"
- Redux Toolkit's
createSliceAPI uses Immer to allow "mutating" immutable updates - Thunks
- For asynchronous logic (AJAX calls)
- Thunks receive
dispatchandgetStateas arguments - Redux Toolkit enables the
redux-thunkmiddleware by default - Component State /
useSelector - React components read data from the store with the
useSelectorhook - Selector functions receive the whole
stateobject, and should return a value - Dispatching actions /
useDispatch createSlicewill generate action creator functions for each reducer we add to a slice- Call
dispatch(someActionCreator())in a component to dispatch an action - Reducers will run, check to see if this action is relevant, and return new state if appropriate
- Using Data
- Components should extract the smallest amount of data they need to render themselves
- Any component can
dispatchactions to cause state updates - Redux action creators can
prepareaction objects with the right contents - Unique IDs and other random values should be put in the action, not calculated in the reducer
- Reducers can contain whatever logic is needed to calculate the next state
- Action objects should contain just enough info to describe what happened
- Async / More on Thunks
- Redux requires plugins/middleware to enable async logic
- The standard async middleware is called
redux-thunk, which is included in Redux Toolkit - Redux Toolkit has a
createAsyncThunkAPI that dispatches these actions for you createAsyncThunkaccepts two arguments:- A string that will be used as the prefix for the generated action types
- A "payload creator" callback that should return a
Promise, and generatespending/fulfilled/rejectedaction types automatically - Generated action creators like
fetchPostsdispatch those actions based on thePromiseyou return - Action creators can be used to automatically fill in the keys of the
extraReducersobject so the slice knows what actions to listen for.
Selectors will re-run whenever the Redux store is updated, and if the data they return has changed, the component will re-render
Temporary data like form input values should be kept as React component state. Dispatch a Redux action to update the store when the user is done with the form.
‣
props, state, and the Redux store to determine what UI they need to render. ‣
createSlice and createAction can accept a "prepare callback" that returns the action payloadReducers should contain the actual state update logic
‣
createSlice using the extraReducers field, and update the state in reducers based on those actions.‣