Home > OS >  Icon change not showing using Redux Tool
Icon change not showing using Redux Tool

Time:01-30

I have a situation here where there are two components. the first component have an input field and the other component is displaying icon and a title name. i used Redux toolkit where when the input field is written anything the icon is changed to another icon. the problem is the icon doesn't change i don't why so, i want to know how to define the icon in the component as shown in my code below.

import { createSlice } from "@reduxjs/toolkit";

const initialState = {
  icon: "unTick",
  value: "",
};

const tickSlice = createSlice({
  name: "tickSign",
  initialState,
  reducers: {
    setValue: (state, action) => {
      state.value = action.payload;
    },
    changeIcon: (state) => {
      if (state.icon === "unTick") {
        state.icon = "tick";
      } else {
        state.icon = "unTick";
      }
    },
  },
});

export const { changeIcon, setValue } = tickSlice.actions;
export const selectValue = (state) => state.value;
export const selectIcon = (state) => state.icon;

export default tickSlice.reducer;

the code of the first component of input

  const value = useSelector(selectValue);
  const dispatch = useDispatch();

  const handleChange = useCallback(
    (e) => {
      dispatch(setValue(e.target.value));
      if (e.target.value.trim().length !== 0) {
        dispatch(changeIcon("tick"));
      } else {
        dispatch(changeIcon("unTick"));
      }
    },
    [dispatch]
  );
<input
            id="boxInput"
            type="text"
            value={value}
            placeholder="Enter Apprenticeship Title"
            onChange={handleChange}
          />

the code for the icon change component

import React from "react";
import { useDispatch, useSelector } from "react-redux";
import { selectIcon } from "../features/TickSlice";
import { TickCircle, UnTickCircle } from "./IconSvg";

const DescNavTitles = ({ title }) => {
  const icon = useSelector(selectIcon);
  const dispatch = useDispatch();

  return (
    <div className="navTitle">
      <svg>{icon === "tick" ? <TickCircle /> : <UnTickCircle />}</svg>
      <p className="navTitle__name">{title}</p>
    </div>
  );
};

export default DescNavTitles;

So, i don't know where exactly should i define the icon to be displayed and changed dynamically

components on the page

Redux tool when written

Redux tool when not written

CodePudding user response:

In the component's render method, you are using the useSelector hook to get the current icon value from the state and conditionally render either TickCircle or UnTickCircle component based on the icon value.

const icon = useSelector(selectIcon);

return (
  <div className="navTitle">
    <svg>{icon === "tick" ? <TickCircle /> : <UnTickCircle />}</svg>
    <p className="navTitle__name">{title}</p>
  </div>
);

Try this.

CodePudding user response:

You are not selecting the icon state correctly. Based on the screen captures showing the Redux state from the devtools your root state has two properties, appren and tick.

The Redux state:

{
  appren: {
    boxItems: [....],
    title: "",
    position: "",
    ...
  },
  tick: {
    icon: "....",
    value: "...."
  },
}

I'm assuming it's this state.tick that is the tickSign slice you are working with. Recall that the useSelector hook callback is passed the entire Redux state object.

const icon = useSelector(state => state.tick.icon);

The selectValue and selectIcon selector functions need to access the correct path to access the expected state properties.

export const selectValue = (state) => state.tick.value;
export const selectIcon = (state) => state.tick.icon;

Additionally, the changeIcon action is only toggling the state value when dispatched, but it seems you want to conditionally set the value from an input element's onChange handler. I suggest the following refactor:

const initialState = {
  isTicked: false,
  value: "",
};

const tickSlice = createSlice({
  name: "tickSign",
  initialState,
  reducers: {
    setValue: (state, action) => {
      state.value = action.payload;
    },
    changeIsTicked: (state, action) => {
      state.isTicked = action.payload;
    },
  },
});

export const { changeIcon, setValue } = tickSlice.actions;
export const selectValue = (state) => state.tick.value;
export const selectIsTicked = (state) => state.tick.isTicked;
const value = useSelector(selectValue);
const dispatch = useDispatch();

const handleChange = useCallback((e) => {
  dispatch(setValue(e.target.value));
  dispatch(changeIsTicked(e.target.value.trim().length !== 0));
}, [dispatch]);

<input
  id="boxInput"
  type="text"
  value={value}
  placeholder="Enter Apprenticeship Title"
  onChange={handleChange}
/>
const DescNavTitles = ({ title }) => {
  const isTicked = useSelector(selectIsTicked);

  return (
    <div className="navTitle">
      <svg>{isTicked ? <TickCircle /> : <UnTickCircle />}</svg>
      <p className="navTitle__name">{title}</p>
    </div>
  );
};

The isTicked state is actually unnecessary though as it can be completely derived from the state.tick.value state value. You can create a selector function that computes this. Example:

const initialState = {
  value: "",
};

const tickSlice = createSlice({
  name: "tickSign",
  initialState,
  reducers: {
    setValue: (state, action) => {
      state.value = action.payload;
    },
  },
});

export const { changeIcon, setValue } = tickSlice.actions;
export const selectValue = (state) => state.tick.value;
export const selectIsTicked = (state) => !!state.tick.value.length;
const DescNavTitles = ({ title }) => {
  const isTicked = useSelector(selectIsTicked);

  return (
    <div className="navTitle">
      <svg>{selectIsTicked ? <TickCircle /> : <UnTickCircle />}</svg>
      <p className="navTitle__name">{title}</p>
    </div>
  );
};
  • Related