У меня есть компонент 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>
@ShubhamVerma Не могли бы вы объяснить? Я не уверен, что понимаю тебя.
укажите идентификатор пути, затем получите к нему доступ через getElementById
Путь динамический, в новостной ленте отображается много постов, и у каждого поста есть своя кнопка для голосования. Я не уверен, как динамически получить путь к кнопке upvote для каждого сообщения.
Вы можете создать 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>
);
}
Почему бы вам не перейти
class
прямо к состоянию?