Home > database >  How can I return state separately when I use redux and array?
How can I return state separately when I use redux and array?

Time:01-16

I'm trying to implement like function by using redux and map function to use states in other components. I used redux not using useState([]) because I thought it is better way to manage states. I made the button changed when button is clicked. But they are sharing same state so it is changed at the same time. To solve this problem, I think I should add this state in array. And here comes my question. How can I add state declared in redux to manage state separately? And is this way correct? I'll upload concrete code including redux by using codesandbox. I'd appreciate it if you let me know, thanks.

Clothes

import React, { useState } from "react";
import styled from "styled-components";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faHeart } from "@fortawesome/free-solid-svg-icons";
import { faHome } from "@fortawesome/free-solid-svg-icons";
import { useDispatch, useSelector } from "react-redux";

const array = [
  {
    id: "1",
    name: "vest",
    img:
      "https://shopimg.kakaofriendsgolf.com/live/images/2022/9/7/10/918997_1662515279620.png",
    price: "10000"
  },
  {
    id: "2",
    name: "shirts",
    img:
      "https://shopimg.kakaofriendsgolf.com/live/images/2022/8/23/18/551886_1661246483199.png",
    price: "12000"
  },
  {
    id: "3",
    name: "pants",
    img:
      " https://shopimg.kakaofriendsgolf.com/live/images/2022/8/22/18/18783_1661159105201.png",
    price: "15000"
  }
];

export default function Clothes() {
  const isClick = useSelector((state) => state.CheckLike.isClick);

  const dispatch = useDispatch();

  // change Icon
  const setHide = (e) => {
    dispatch({ type: "False" });
  };

  const setShow = (e) => {
    dispatch({ type: "True" });
  };

  return (
    <Wrap>
      <div className="productCard">
        {array.map((content, idx) => {
          return (
            <div key={idx} className="productCard__wrap">
              <img src={content.img} className="productCard__img" />
              <div className="productCard__name">
                <div>
                  <h3 className="productCard__title">{content.name}</h3>
                  <div className="productCard__priceWrap">
                    {content.price
                      .toString()
                      .replace(/\B(?=(\d{3}) (?!\d))/g, ",")}
                  </div>
                </div>
                <div className="productCard__likeWrap">
                  {/* show heart and house icon according to state */}
                  {isClick ? (
                    <div
                      onClick={() => {
                        setHide();
                      }}
                    >
                      <FontAwesomeIcon icon={faHeart} />
                    </div>
                  ) : (
                    <div
                      onClick={() => {
                        setShow();
                      }}
                    >
                      <FontAwesomeIcon icon={faHome} />
                    </div>
                  )}
                </div>
              </div>
            </div>
          );
        })}
      </div>
    </Wrap>
  );
}

const Wrap = styled.div`
  position: fixed;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  overflow: scroll;

  .productCard {
    display: flex;
    position: absolute;
    top: calc(50vh - 120px);
    left: calc(50vw - 180px);
    width: "228px";
    height: "351px";
    padding-right: 8px;
    padding-left: 8px;
    border: solid 1px black;
  }

  .productCard__wrap {
    border: 1px solid grey;
    line-height: 1.428571429;
    background-color: #fff;
  }

  .productCard__img {
    width: 228px;
    height: 228px;
  }

  .productCard__name {
    padding-bottom: 30px;
    position: relative;
    padding: 8px 8px 0 8px;
    min-height: 118px;
    text-align: left;
  }

  .productCard__title {
    font-size: 18px;
    margin-top: 0;
    margin-bottom: 2px;
    padding-right: 37px;
    line-height: 1.3;
    margin-block-start: 1em;
    margin-block-end: 1em;
  }

  .productCard__priceWrap {
    font-size: 18px;
    margin-top: 5px;
    vertical-align: middle;
    margin: 0 0 9px;
    margin-block-start: 1em;
    margin-block-end: 1em;
    text-align: left;
  }

  .productCard__likeWrap {
    position: absolute;
    top: -5px;
    right: 0;
    padding: 0;
    height: 40px;
    line-height: 37px;
    white-space: normal;
    display: inline-block;
    margin-bottom: 0;
    font-weight: normal;
    text-align: center;
  }
`;

codesandbox

https://codesandbox.io/s/likepractice-tpcv7l?file=/src/components/Clothes.jsx

CodePudding user response:

There could be many approaches, but assuming that the goal is to make the like button work for individual items and save the liked items in the store, I think the solution of using an array as a state is suitable in the use case.

Forked demo with modification: codesandbox

Configure the state as an array and create matching reducers, here the product id is saved to the state array when liked, but this is an optional approach.

const initailState = {
  isClick: [],
};

const CheckLike = (state = initailState, action) => {
  switch (action.type) {
    case "True":
      return {
        ...state,
        isClick: [...state.isClick, action.id],
      };

    case "False":
      return {
        ...state,
        isClick: state.isClick.filter((id) => id !== action.id),
      };

    default:
      return {
        ...state,
      };
  }
};

Edit the event handler to dispatch the item id to be added or removed from the state array:

const setHide = (id) => {
  dispatch({ type: "False", id });
};

const setShow = (id) => {
  dispatch({ type: "True", id });
};

Check if product id content.id is included in the state array as a condition for rendering the icons, and wire up the icons to send content.id to the events:

<div className="productCard__likeWrap">
  {isClick.includes(content.id) ? (
    <div
      onClick={() => {
        setHide(content.id);
      }}
    >
      <FontAwesomeIcon icon={faHeart} />
    </div>
  ) : (
    <div
      onClick={() => {
        setShow(content.id);
      }}
    >
      <FontAwesomeIcon icon={faHome} />
    </div>
  )}
</div>

CodePudding user response:

if I'm guessing correctly your problem is that the button click changes all the buttons.

for this issue, you don't need redux. use redux when you want to manage a global state used in multiple components(ex, session).

solution for your problem is, create a new component for each product card and there manage the state of the button.

and to store which products are on the wishlist you can store that in redux.

  • Related