Redux and reducers, how to use them in a react app

Viewed 42

I have different packages for a product that you can choose from. When you choose a package a side modal opens where you must confirm the package you have chosen and make payment.

I have made a reducer to help with storing the data once you choose an option.

What i am confused about is how you actually use the reducer to show the chosen package in the side screen?

My code is as follows:

The reducers:

import { createSlice, PayloadAction } from '@reduxjs/toolkit';
import { RootState } from '../store';

export interface PackageState {
  billingCycle: string;
  packageOption: string;
}

const initialState: PackageState = {
  billingCycle: 'Monthly',
  packageOption: 'Free',
};

export const PackageSlice = createSlice({
  name: 'packageSlice',
  initialState,
  reducers: {
    setBillingCycle: (state, action: PayloadAction<string>) => {
      state.billingCycle = action.payload;
    },
    setPackage: (state, action: PayloadAction<string>) => {
      state.packageOption = action.payload;
    },
  },
});

export const { setBillingCycle, setPackage } = PackageSlice.actions;
export const packageSelector = (state: RootState) => state.packageReducer;

export default PackageSlice.reducer;

The actions:

import { AppDispatch, AppThunk } from '../store';
import { setBillingCycle, setPackage } from './packages.reducer';

export const setBillingCycleAction =
  (billingCycle: string): AppThunk =>
  (dispatch: AppDispatch) => {
    return dispatch(setBillingCycle(billingCycle));
  };

  export const setPackageAction =
      (packageOption: string): AppThunk =>
      (dispatch: AppDispatch) => {
        return dispatch(setPackage(packageOption));
      };

And the side modal where I want the data to change base on the package you have chosen:

import React, { useState } from 'react';
import { useSelector } from 'react-redux';
import { packageSelector } from '../../../reducers/packages-reducer/packages.reducer';

export const ConfirmPackagesscreen: React.FC = () => {
  const [openModal, setOpen] = useState(true);
  const history = useHistory();
  const packageOption = useSelector(packageSelector);


  const handleClose = () => {
    setOpen(false);
    history.push('/');
  };

  return (
    <RecaptchaContainer>
      <Modal
        open={openModal}
        onClose={handleClose}
        disableScrollLock
      >
        <Box sx={boxStyle}>
          <div className="form-container mt-11">
            <div className="mt-2 mx-9 font-Poppins">
              <div>
                <p className="font-semibold text-base text-black">Package Deatails</p>
              </div>
              <div className="flex justify-between font-normal text-sm my-3">
                <p>[package name]</p>
                <p>[billing cycle. yearly or monthly]</p>
              </div>
              <div className="flex justify-between font-normal text-sm my-3">
                <p>Amount</p>
                <p>[price]</p>
              </div>
              <Divider className="bg-dividerColor" />
            </div>
            <div className="flex justify-center w-65 mt-12">
              <button
                type="button"
                onClick={undefined}
                className="font-nunito font-bold edit-user-button mt-4 py-2.5 px-16"
              >
                Make Payment
              </button>
            </div>
          </div>
        </Box>
      </Modal>
    </RecaptchaContainer>
  );
};

Example of the different package options:

 const MonthCards = () => {
    return (
        <Card className="packagesCard shadow-customShadow w-80">
          <CardContent>
            <div>
              <p className="text-2xl font-Poppins">Free</p>

            </div>
            <div className="my-3 flex">
              <p className="text-lg">Free</p>
              <p className="text-3xl ml-16">R0.00</p>
            </div>
            <Divider className="bg-dividerColor" orientation="horizontal" />
            <div className="flex justify-center my-3">
              <Button
                className="bg-mainBlue w-64 text-white hover:bg-blue-800 text-base"
                onClick={handleRegister}
              >
                Get Started
              </Button>
            </div>
          </CardContent>
        </Card>
        <Card className="packagesCard shadow-customShadow w-80">
          <CardContent>
            <div>
              <p className="text-2xl font-Poppins">Pro</p>
              <Divider className="bg-dividerColor" orientation="horizontal" />
            </div>
            <div className="my-3">
              <p className="text-3xl ml-20">
                R39.99 &nbsp;<span className="text-sm font-light">incl. VAT</span>
              </p>
            </div>
            <Divider className="bg-dividerColor" orientation="horizontal" />
            <div>
              <div className="flex justify-center my-3">
                <Button
                  className="bg-mainBlue w-64 text-white hover:bg-blue-800 text-base"
                  onClick={handleRegister}
                >
                  Try it free
                </Button>
              </div>
              <div className="flex justify-center">
                <Button
                  className="text-mainBlue hover:bg-blue-800 hover:bg-opacity-20"
                  onClick={handleRegister}
                >
                  Purchase Now
                </Button>
              </div>
            </div>
          </CardContent>
        </Card>
        <Card className="packagesCard shadow-customShadow w-80">
          <CardContent>
            <div>
              <p className="text-2xl font-Poppins">Team</p>
              <Divider className="bg-dividerColor" orientation="horizontal" />
            </div>
            <div className=" my-3">
              <p className="text-3xl ml-20">
                R44.99 &nbsp;<span className="text-sm font-light">incl. VAT</span>
              </p>
            </div>
            <Divider className="bg-dividerColor" orientation="horizontal" />
            <div>
              <div className="flex justify-center my-3">
                <Button
                  className="bg-mainBlue w-64 text-white hover:bg-blue-800 text-base"
                  onClick={handleRegister}
                >
                  Try it free
                </Button>
              </div>
              <div className="flex justify-center">
                <Button
                  className="text-mainBlue hover:bg-blue-800 hover:bg-opacity-20"
                  onClick={handleRegister}
                >
                  Purchase Now
                </Button>
              </div>
            </div>
          </CardContent>
        </Card>
      </div>
    );
  };
1 Answers

If your redux reducers have been setup properly, you can easily access the data by surrounding your values in {} in the return statement. Doing so allows you to run javascript related to objects, mapping, and ternary conditionals. Below is the modified component code:

import { useSelector } from 'react-redux';
import { packageSelector } from '../../../reducers/packages-reducer/packages.reducer';

export const ConfirmPackagesscreen: React.FC = () => {
  const [openModal, setOpen] = useState(true);
  const history = useHistory();
  const packageOption = useSelector(packageSelector);


  const handleClose = () => {
    setOpen(false);
    history.push('/');
  };

  return (
    <RecaptchaContainer>
      <Modal
        open={openModal}
        onClose={handleClose}
        disableScrollLock
      >
        <Box sx={boxStyle}>
          <div className="form-container mt-11">
            <div className="mt-2 mx-9 font-Poppins">
              <div>
                <p className="font-semibold text-base text-black">Package Deatails</p>
              </div>
              <div className="flex justify-between font-normal text-sm my-3">                
                {/* update this */}
                <p>{packageOption.name}</p>
                <p>{packageOption.billingCycle}</p>
              </div>
              <div className="flex justify-between font-normal text-sm my-3">
                <p>Amount</p>
                {/* update this */}
                <p>{packageOption.price}</p>
              </div>
              <Divider className="bg-dividerColor" />
            </div>
            <div className="flex justify-center w-65 mt-12">
              <button
                type="button"
                onClick={undefined}
                className="font-nunito font-bold edit-user-button mt-4 py-2.5 px-16"
              >
                Make Payment
              </button>
            </div>
          </div>
        </Box>
      </Modal>
    </RecaptchaContainer>
  );
};

This is the modified reducer code to ensure you have all the props you are displaying in the component coming from redux:

import { createSlice, PayloadAction } from '@reduxjs/toolkit';
import { RootState } from '../store';

export interface PackageState {
  name: string; 
  price: number;
  billingCycle: string;
  packageOption: string;
}

const initialState: PackageState = {
  name: "Super"
  price: 10,
  billingCycle: 'Monthly',
  packageOption: 'Free',
};

export const PackageSlice = createSlice({
  name: 'packageSlice',
  initialState,
  reducers: {
    setBillingCycle: (state, action: PayloadAction<string>) => {
      state.billingCycle = action.payload;
    },
    setPackage: (state, action: PayloadAction<string>) => {
      state.packageOption = action.payload;
    },
  },
});

export const { setBillingCycle, setPackage } = PackageSlice.actions;
export const packageSelector = (state: RootState) => state.packageReducer;

export default PackageSlice.reducer;

If this doesn't work, make sure you check that your redux store was initialized properly.

Related