Home > Back-end >  Why is my react redux state not causing a re-render?
Why is my react redux state not causing a re-render?

Time:05-29

Hello i've an issue where my redux state not causing a re-render when i'm trying to use a selector. I'm pretty new to react-redux and typescript. I've been trying to google this and most internet threads say it's because you need to create a new object and return that to let redux know that state has changed. Which im already doing. But my object is not re-rendering, the state IS updated but not causing a rerender.

What am i doing wrong?

My Redux reducer


import { Computer, GraphicsCard } from "../../interfaces";

const initialState: Computer = {
    graphicsCard: null,
}


interface SelectGraphicsCardAction {
    type: "SELECT_GRAPHICSCARD";
    payload: GraphicsCard;
}

interface UnselectGraphicsCardAction {
    type: "UNSELECT_GRAPHICSCARD";
}


export type Action = SelectGraphicsCardAction | UnselectGraphicsCardAction

export const computerReducer = (state = initialState, action: Action) => {
    switch(action.type){
        case "SELECT_GRAPHICSCARD": {
            const { payload } = action;
            console.log(state, payload)

           const newState = {
                ...state,
                graphicsCard: {
                    ...state.graphicsCard,
                    ...payload
                }
            }
            //This evaluates to false
            console.log(state === newState)

            return newState
        }
        case "UNSELECT_GRAPHICSCARD": {
            return {
                ...state,
                graphicsCard: null
            }
        }
        default:
            return state;
    }

} 

My Redux Store

import { configureStore } from '@reduxjs/toolkit'
import { computerReducer } from './reducers/ComputerReducer'
// ...

 export const store = configureStore({
  reducer: {
    computer: computerReducer
  },
})

Im selecting/using the state here.

function SelectedComputer() {
  const computer = useSelector((state: Computer) => state);
  const dispatch = useDispatch();
  const { graphicsCard } = computer;

  //Logging correct state
  console.log(computer)

  return (
    <div className="fixed top-10 right-4 bg-white rounded-t-lg">
      <p className="text-center font-bold border-b-1 border-b-black bg-gray-100 rounded-t-lg shadow-md">
        Selected Parts
      </p>
      <div className="flex flex-row">
        <CpuFill className="m-1" />
        {graphicsCard ? (
          //Not rendering this when updating state.
          <p>{graphicsCard.name}</p>
        ) : (
          <p>No Graphicscard selected!</p>
        )}
        <Trash className="flex justify-center"/>
      </div>

EDIT: Here is a snippet where am using dispatch to update the state.

import React, { FC } from "react";
import { Button, Card } from "react-bootstrap";
import { useDispatch } from "react-redux";
import { Component, ComputerComponent } from "../interfaces";
import { Action } from "../redux/reducers/ComputerReducer";

interface ComponentCard {
  component: Component;
  buttonText: string;
  type: string;
}

interface DomainImage {
  [key: string]: string;
}

const ComponentCard: FC<ComponentCard> = ({ component, buttonText, type }) => {
  const dispatch = useDispatch();

  const imageMap: DomainImage = {
    "inet.se": "https://cdn.inet.se/gfx/ext/226/brand-assets/inet-logo2.jpg",
    "komplett.se":
      "https://cached-images.bonnier.news/gcs/di-bilder-prod/mly/fcb28d10-158c-485b-814c-b461baa0e188.jpeg",
    "webhallen.se":
      "https://static.wikia.nocookie.net/logopedia/images/6/65/Webhallen_2021.svg/revision/latest?cb=20220420201224",
  };

  return (
    <Card className="flex flex-row items-center w-50 shadow-md mt-2 mb-2">
      <div className="flex justify-center items-center mr-3">
        <img className="h-36 w-40 p-2" src={component.imgUrl} />
      </div>
      <div className="flex-1 text-left">
        <h4 className="text-base">{component.name}</h4>
        <p>
          <span>
            ArtNr: {component.articleNumber}, Manufacturer:{" "}
            {component.manufacturer}
          </span>
        </p>
        <h4 className="absolute right-36 top-10">
          <span>{component.price} :-</span>
        </h4>
      </div>
        <Button
          color=""
          className="absolute right-5 h-10 w-20"
          onClick={() => dispatch({ type, payload: component })}
        >
          {buttonText}
        </Button>
        <a href={component.url} target="_blank" className="absolute right-5 bottom-0">
          <img
            className="w-15 h-10"
            src={imageMap[component.domainName]}
            alt={component.name}
          />
        </a>
    </Card>
  );
};

CodePudding user response:

For what it's worth, you are using an extremely outdated (pre-2019) style of Redux here that will end up being about 4x the code you would write with modern Redux - especially in combination with TypeScript.

I would highly recommend you to follow the official Redux tutorial and the TypeScript QuickStart that will show you all the additional types you have to set up (it's a lot less than what you have right now).

The source of your problem is likely an accidental state modification, which can also happen outside of reducers in legacy Redux - in modern Redux you would get an error immediately at the point where you make the mutation - saving you hours of debugging. So I'd really recommend you just switch over and you'll probably be rid of this bug.

  • Related