根据 'liked' 状态更改 SVG 图标颜色

Change SVG icon color based on 'liked' status

我的 React/TypeScript 应用程序中有一个点赞组件,允许用户点赞 post,或删除他们的点赞。 upvote 本身是来自 react-icons 包的图标,特别是来自 Grommet-Icons 部分。当用户通过单击图标为 post 投票时,我会动态更改图标的填充,如下所示:

e.target.querySelector("path").setAttribute("fill", "green");

e.target 是一个 SVG 元素。在该元素中,我使用 querySelector 找到它的 path child。在 path child 上,我将其 'fill' 属性设置为绿色。

这很好用,但我想扩展它。当我呈现每个 post 时,我检查登录的用户是否已经对特定的 post 投了赞成票。我想根据用户是否已经投票 post 的布尔结果更改图标的颜色,这样图标就可以已经是绿色的,用户会看到他们已经投票 post。我的问题是如何在没有 e.target 的情况下访问 'fill' 属性- 因为用户在页面加载时没有单击任何内容。我想我的问题非常具体到 react-icons 包的用法,因为当我向我的 return 函数添加图标时,它被包装器组件包装,所以我无法访问 path 元素(在本例中,组件是 GrSign)。

这是上下文的 Upvote 组件:

import React, { useEffect, useState } from "react";
import { GrSign } from "react-icons/gr";
import { useSelector } from "react-redux";
import { InitialState } from "../store/reducers/rootReducer";

export const Upvote = (props: any) => {

const userState = useSelector((state: InitialState) => {
    return state.auth;
  });

const [upvoted, setUpvoted] = useState(false);

  useEffect(() => {
    if (userState && userState.user !== undefined) {
      const userId = userState.user.user._id;
      if (props.upvotes.indexOf(userId) > -1) {
        // The user already upvoted this post
        setUpvoted(true);
      }
    }

    if (upvoted) {
        
    }
  }, []);

const handleClick = (e: any) => {
    console.log(e.target);
    e.target.querySelector("path").setAttribute("fill", "red");
  };
 
  return (
    <div className="flex items-center">
      <GrSign
        size="2em"
        className="transform transition duration-300 hover:scale-125"
        onClick={handleClick}
      />
      <div className="pl-2 text-lg">{props.upvotes.length}</div>
    </div>
  );
};

useEffect 函数中,如果 upvoted === true.

我想添加一行来改变图标的​​颜色

为了以防万一,这是我在 handleClick 函数中写入 console.log(e.target) 时打印到控制台的内容:

<svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 24 24" class="transform transition duration-300 hover:scale-125" height="2em" width="2em" xmlns="http://www.w3.org/2000/svg"><path fill="red" stroke="#000" stroke-width="2" d="M8,23 C10,23 12.9996892,23 15,23 C18,23 19,21 19,18 L19,6 C19,4.00000008 18,3.99999992 17.5,4 C17,4.00000008 15.9998779,4.00000008 15.9998779,5.99999984 L15.9998779,13 C15.9998777,12 16.0001888,10.9999999 14.5003109,10.9999999 C13.000433,10.9999999 13,13 13,13 C13,12 13,11 11.5,10.9999999 C10,10.9999999 10,12 10,12.9999999 L10,4 C10,3 10.029402,2 8.5,2 C7,2 7,3 7,4 L7,18 L7,14 C7,13 6.44999986,12 5.00000005,12 C5,12 4,12 4,12 C4,12 4.00000001,14.0384045 4,18 C3.99999999,21.9615955 6,23.023861 8,23 Z"></path></svg>

您可以为图标容器创建一个ref。还要添加一个新的 useEffect 块,每次投票 属性 更改时都会执行该块:

export const Upvote = (props: any) => {
      //...
      const [upvoted, setUpvoted] = useState(false);
      const iconRef = useRef(null);
    
      useEffect(() => {
        if (userState && userState.user !== undefined) {
          const userId = userState.user.user._id;
          if (props.upvotes.indexOf(userId) > -1) {
            // The user already upvoted this post
            setUpvoted(true);
          }
        }
      }, []);
    
      useEffect(() => {
        if (upvoted) {
             iconRef.current.querySelector("svg path").setAttribute("fill", "red")
        }
      }, [upvoted]);
    
      const handleClick = e => {
        //...
      };
      return (
        <div className="flex items-center" ref={iconRef}>
          <GrSign
            size="2em"
            className="transform transition duration-300 hover:scale-125"
            onClick={handleClick}
          />
          <div className="pl-2 text-lg">{upvotes.length}</div>
        </div>
      );
    }