ProNextJS
    exercise

    Using Redux in an App Router Application

    Jack HerringtonJack Herrington

    Now that we have our React version of our application all ready to go, it's time to start thinking about how to use a state manager in the App Router.

    Redux is the OG state manager, and follows a simple, three-part model:

    First, there's a Store that holds your data. Then there are Selectors which you can use in your components to get access to the data in that store. Finally, there are Actions that are dispatched to the Redux store. These actions are then handled by reducers that mutate the data in the store.

    Redux has a nice unidirectional flow: Actions go into the store, and trigger mutations. The mutations essentially trigger the selectors, which then update the display of the data on the page.

    In a traditional Redux setup, there is only a single store. That single store is just declared as a global variable, often in a store.ts file.

    However, that's not going to work in our case because "Rule Number One" says no global variables!

    Challenge

    In this challenge, you'll be implementing a Redux store using context instead of relying on a global variable.

    Starting with the 03-cart-context-with-initial-state example we just finished, you'll need to remove the existing CartContext object and replace it with a Redux store.

    You'll need to install redux, react-redux and @reduxjs/toolkit.

    You'll need to remove the existing CartContext object and replace it with a Redux store.

    Remember, you cannot safely use a Redux store that is defined as a global store.

    Redux Example

    Here is an example of a count slice created with Redux Toolkit:

    import { configureStore } from "@reduxjs/toolkit";
    import { createSlice } from "@reduxjs/toolkit";
    import type { PayloadAction } from "@reduxjs/toolkit";
    
    export interface CounterState {
    	count: number;
    }
    
    const initialState: CounterState = {
    	count: 0,
    };
    
    export const countSlice = createSlice({
    	name: "count",
    	initialState,
    	reducers: {
    		setCount: (state, action: PayloadAction<number>) => {
    			state.count = action.payload;
    		},
    	},
    });
    

    Here is an example createStore function that creates a new Redux store.

    export const createStore = () =>
    	configureStore({
    		reducer: {
    			count: countSlice.reducer,
    		},
    	});
    

    Here is a way to export the setCount action, as well as handy types and a selector for the count:

    import { useSelector } from "react-redux";
    
    export const { setCount } = countSlice.actions;
    
    export type StoreType = ReturnType<typeof createStore>;
    export type RootState = ReturnType<StoreType["getState"]>;
    export type AppDispatch = StoreType["dispatch"];
    
    export const useCount = () =>
    	useSelector((state: RootState) => state.cart.cart);
    

    To dispatch actions to the store use useDispatch to get a dispatch function. You use it like this:

    dispatch(setCount(42));
    

    Give it a try, and we'll walk through it together in the next video!

    Transcript

    Now that we have our react version of our application all ready to go, it's time to start thinking about how to use a state manager in the app writer. And there's no more OG state manager than Redux. Now Redux is a pretty simple model. There's basically three parts to it. There is the

    store that holds your data. There are selectors, which you can use in your components to get access to the elements of the store, the data in that store. And there are actions. And you dispatch

    actions to the Redux store. And then those actions then are handled by reducers that mutate the data in the store. And you get this nice unidirectional flow. So actions go into the store. Those trigger

    mutations. Mutations essentially trigger the selectors, which then update the display of the data on the page. Now in a traditional Redux setup, you have a single store. And that single store is just declared as a global variable sitting in probably a store.ts implementation file.

    And you can access the store directly as a global variable. That's not going to work because rule number one says no global variables. So that's actually what we're going to work through in this exercise. We're going to figure out how to share around a Redux store using context instead of a

    global variable. And then we'll see later on what the ramifications of that are as we get into the next exercise. Okay, so the objective here is to reimplement just the cart using Redux, starting with the 03 cart context with initial state example that we went through. Of course, if you have any

    questions about how to use Redux, be sure to consult the resources. Good luck.