Изменить цвет значка SVG в зависимости от статуса «нравится»

У меня есть компонент Upvote в моем приложении React/TypeScript, который позволяет пользователю голосовать за сообщение или удалять свой голос. само голосование — это значок из пакета 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.info(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.

На всякий случай, если это поможет, вот что выводится на консоль, когда я пишу console.info(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>

Почему бы вам не перейти class прямо к состоянию?

Shubham Verma 22.12.2020 13:34

@ShubhamVerma Не могли бы вы объяснить? Я не уверен, что понимаю тебя.

Gavi Schneider 22.12.2020 13:35

укажите идентификатор пути, затем получите к нему доступ через getElementById

Robert Longson 22.12.2020 13:43

Путь динамический, в новостной ленте отображается много постов, и у каждого поста есть своя кнопка для голосования. Я не уверен, как динамически получить путь к кнопке upvote для каждого сообщения.

Gavi Schneider 22.12.2020 13:45
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
2
4
409
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы можете создать 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>
      );
    }

Другие вопросы по теме