To see the code in work, see the GitHub repository here

Redux Toolkit utilization allows our app to access and update state variables that are shared between our components. Our components, which in one way or the other need access to state variables access the state and update the state via “reducers”.

We first set up a Redux store that has reference to all our reducers sitting in their respective files. An example of a store is as below:

//store.tsx

import { configureStore } from "@reduxjs/toolkit";
//Importing the reducer form countSlice
//import counterReducer from "./countslice"
import initialDetailsReducer from "./initialDetailsSlice"
//import componentsToRenderReducer from "./componentRenderSlice"
import dataModelReducer from "./dataModelSlice"



export const store = configureStore({
//const store = configureStore({
    reducer: {
        initialDetails: initialDetailsReducer,
        dataModel: dataModelReducer
    },
    //setting the serializableCheck flag to false so that Date variable is put in without serialization. Otherwise serialize date with eg: date.toISOString();
    middleware: (getDefaultMiddleware) => getDefaultMiddleware({
            serializableCheck: false
    })
})
//export type AppDispatch = typeof store.dispatch;
//wrong: export type AppDispatch = ReturnType<typeof store>["dispatch"]
//export default store;

We then set up “slices” where we focus on groups of related state variables in one place. The “slice” will have an “initial state” and a set of reducers in the slice. An example is the following slice:

import { createSlice } from '@reduxjs/toolkit'

const initialState = {
    numberOfDays: 7,
    startDate: new Date(),
    kommunId: "kommun1",
    kommunName: "Kommun 1",
    clusterId: 0,
    clusterTitle: "",
    clusterVerksamheter_och_omrade: "Not entered yet",
}

export const initialDetailsSlice = createSlice({
    name: 'initialDetails',
    initialState,
    reducers: {
        setNumberOfDays: (state, action) => {
            state.numberOfDays = action.payload
            console.log("- got dispatch req for setNumberOfDays and set to: " + state.numberOfDays)
        },
        setStartDate: (state, action) => {
            state.startDate = action.payload
            console.log("calendar Date (of type Date) in store now: " + state.startDate)

        },
        updateClusterId: (state, action) => {
            state.clusterId = action.payload
            console.log("- update state.clusterId to: " + state.clusterId)
        },
        updateClusterTitle: (state, action) => {
            state.clusterTitle = action.payload
            console.log("- update state.clusterTitle to: " + state.clusterTitle)
        },
        updateClusterVerksamheterOchOmrade: (state, action) => {
            state.clusterVerksamheter_och_omrade = action.payload
            console.log("- updated state.clusterName to: " + state.clusterVerksamheter_och_omrade)
        },
    },
})

export const { setNumberOfDays, setStartDate,
    updateClusterId, updateClusterTitle,
    updateClusterVerksamheterOchOmrade } = initialDetailsSlice.actions

export default initialDetailsSlice.reducer

And last but not least, we import the reducers from the slices. We then call the state variables and set them through “dispatch”:

import * as React from 'react';
import {useState, useEffect} from 'react';
import axios from 'axios';
import { useSelector, useDispatch } from 'react-redux';
//import { configureStore } from '@reduxjs/toolkit';
import { ThunkDispatch } from '@reduxjs/toolkit';
import configData from "./config.json"

import { setNumberOfDays, setStartDate, updateClusterId,
          updateClusterTitle, updateClusterVerksamheterOchOmrade
       } from './initialDetailsSlice';
import { setDataModel, saveDataModelAsDraftOrPublish, loadTheRecordIntoScreen } from './dataModelSlice';


function App() {
  //const dispatch = useDispatch<AppDispatch>();
  //const dispatch = useDispatch();
  const dispatch = useDispatch<ThunkDispatch<any,any,any>>();

  const [userIsLoggedIn, setUserIsLoggedIn] = useState(false);
  const [userRole, setUserRole] = useState("NA");
  const [userEmail, setUserEmail] = useState("");
  const [userPassword, setUserPassword] = useState("");
  const [userFirstName, setUserFirstName] = useState("");

  let [renderedTemplate, setRenderedTemplate] = useState(<div></div>)
  let numDays = useSelector((state:any) => state.initialDetails.numberOfDays);
  let startDate = useSelector((state:any)=>state.initialDetails.startDate)
  let clusterId = useSelector((state:any) => state.initialDetails.clusterId);
  let clusterTitle = useSelector((state:any) => state.initialDetails.clusterTitle);
  let clusterVerksamheter_och_omrade = useSelector((state:any) => state.initialDetails.clusterVerksamheter_och_omrade);
  
  let dataModel = useSelector((state:any)=>state.dataModel.dataModel);
  let id = useSelector((state:any)=>state.dataModel.id);
  let publishStatus = useSelector((state:any)=>state.dataModel.publishStatus);
  
  function handleClusterListChange(e:any) {
    //set the cluster id for the entry
    console.log("set cluster details according to: " + JSON.stringify(e))
    dispatch(updateClusterVerksamheterOchOmrade("Verksamhet 2"))
    dispatch(updateClusterId(2))
  }

  const auth = async() => {
    console.log("- Authorize " + userEmail + "...")
    try {
      const res = await axios
          .post(configData.API_URL+"login",
          { email: userEmail,
             password: userPassword,
                clusterId: clusterId },
          { withCredentials: true }

       );
       const response = res.data;
       //alert("response: " + JSON.stringify(response))
       if (response.message == "User not OK") {
         console.log("Fel med inloggning: " + response.description)
       } else if (response.message == "User OK") {
                /*example response:
                message:	"User OK"
                sessionId:	"80457f3e-d9f9-4725-9a04-6d0eccd8d28f"
                firstName:	"Tom"
                role:	"User"*/
            console.log("sessionID: " + response.sessionId);
            setUserIsLoggedIn(true);
            setUserRole(response.role)
            setUserFirstName(response.firstName)
   
       }
      //alert (JSON.stringify(res.data));
      /*if (res.data.screen !== undefined) {
        setScreen(res.data.screen);
      }*/
    } catch (e) {
      console.log("-There was an error in axios's retrieving: "+e);
    }
  }

return (
      <div className="App">
        { }
        {/*<button onClick={()=>alert(dataModel.dates)}>dataModel.dates</button>
        <button onClick={showDataModel}>Show dataModel</button>
        <button onClick={showSessionID}>showSessionID</button> 
        */}
        { userIsLoggedIn &&
        <div className={"topRibbon"+userRole}>
          <div className="alignLeft">
            Välkommen {userFirstName}! 
          </div>
        </div>
        }

        { userIsLoggedIn==true &&
          userRole=="Admin" &&
          <div id="AdminContent">
            <p>Arbeta med schemat enligt följande detaljer:</p>
  
            {renderedTemplate}
          </div>    
        }

        { userIsLoggedIn==true &&
          userRole=="User" &&
          <div id="UserContent">
            <p></p>

            <div data-id="allEditables">  
            {renderedTemplate}
          </div>
          </div>
        }
        <button onClick={()=>(handleClusterListChange("verksamhet 2"))}>
          React App 1 - Click button dispatch cluster list handleClusterListChange
        </button>
        <p>clusterVerksamheter_och_omrade value (state value in slice)= </p>
        {clusterVerksamheter_och_omrade}


  </div>
)
}

export default App;

And that is how Redux Toolkit can be used in a React functional app. To see the code in work, see the GitHub repository here

Leave a Reply

Your email address will not be published. Required fields are marked *