2

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

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

e.target是一个 SVG 元素。在那个元素中,我querySelector用来找到它的path子元素。在path孩子身上,我将其“填充”属性设置为绿色。

这工作正常,但我想扩展它。当我呈现每个帖子时,我会检查登录的用户是否已经投票支持该特定帖子。我想根据用户是否已经对帖子进行投票的布尔结果来更改图标的颜色,这样图标就可以是绿色的,并且用户会看到他们已经对帖子进行了投票。我的问题是如何在没有 - 的情况下访问该“填充”属性,e.target因为用户在页面加载时没有点击任何内容。我想我的问题非常具体到react-icons包的使用,因为当我向我的返回函数添加一个图标时,它被一个包装组件包装,所以我无法访问该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函数中,我想添加一条线来改变图标的​​颜色 if upvoted === true

以防万一这有帮助,这是我console.log(e.target)在函数内部编写时打印到控制台的内容handleClick

<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>
4

1 回答 1

1

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

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>
      );
    }
于 2020-12-22T12:56:09.503 回答