#javascript #html #reactjs #html5-canvas
Вопрос:
Есть ли способ динамически изменять цвета lt;IconTint /gt;
элемента из react-icon-tint
библиотеки? Мне нужно, чтобы цвет менялся при isActive
изменении состояния, но, похоже, он работает не так, как я ожидал, потому что он использует canvas
элемент под капотом.
Я также попытался перенаправить весь элемент на isActive
изменение таким образом
{ isActive ? ( lt;IconTint src={getCustomIcon()} color={icon} /gt; ) : ( lt;IconTint src={getCustomIcon()} color={iconOnBackground} /gt; ); }
Но и это тоже не сработало.
Ответ №1:
Я просмотрел исходный код, потому что это компонент с памятью, он не повторяется при повторной передаче родительского кода, и поскольку внутри эффекта использования, используемого внутри компонента, зависимости, такие как src цвета и изображения, не включены, он не повторяется при изменении реквизита, очевидно, это ошибка или нежелательное поведение. Я не знаю, почему ваш способ сделать это не работает, потому что эти два компонента IconTint-это два разных компонента!. но вы можете сделать это таким образом:
{isActive amp;amp; lt;IconTint src={getCustomIcon()} color='#0000ff' /gt;} {!isActive amp;amp; lt;IconTint src={getCustomIcon()} color='#b43285' /gt;}
Я не думаю, что это эффективно, исходный код настолько прост, что вы можете реализовать IconTint внутри своего проекта и просто добавить зависимости внутри массива зависимостей useEffect. Здесь я предоставил измененную версию.
import React, { memo, useEffect, useRef, useState } from "react"; import PropTypes from "prop-types"; const IconTint = ({ fallback = lt;span /gt;, src, color, maxWidth, maxHeight }) =gt; { const canvasRef = useRef(null); const [size, setSize] = useState({}); const _scaleImage = (srcWidth, srcHeight, maxWidth, maxHeight) =gt; { if (maxWidth amp;amp; maxHeight) { const ratio = Math.min(maxWidth / srcWidth, maxHeight / srcHeight); return { width: srcWidth * ratio, height: srcHeight * ratio }; } if ((maxWidth amp;amp; !maxHeight) || (!maxWidth amp;amp; maxHeight)) { throw new Error( "If you are going to provide width, make sure to provide height as well" ); } return { width: srcWidth, height: srcHeight }; }; useEffect(() =gt; { const canvas = canvasRef.current; // eslint-disable-next-line no-undef const pic = new Image(); pic.src = src; const tintCanvas = document.createElement("canvas"); const tintCtx = tintCanvas.getContext("2d"); const ctx = canvas.getContext("2d"); pic.onload = () =gt; { const result = _scaleImage(pic.width, pic.height, maxWidth, maxHeight); setSize(result); tintCanvas.width = result.width; tintCanvas.height = result.height; tintCtx.fillStyle = color; tintCtx.fillRect(0, 0, result.width, result.height); tintCtx.globalCompositeOperation = "destination-atop"; tintCtx.drawImage(pic, 0, 0, result.width, result.height); ctx.globalAlpha = 1; ctx.drawImage(tintCanvas, 0, 0, result.width, result.height); }; }, [src,color,maxHeight,maxWidth]); if ( typeof window !== "undefined" amp;amp; window.document amp;amp; window.document.createElement ) { return lt;canvas width={size.width} height={size.height} ref={canvasRef} /gt;; } return fallback; }; IconTint.propTypes = { src: PropTypes.string.isRequired, color: PropTypes.string.isRequired, fallback: PropTypes.node, maxWidth: PropTypes.number, maxHeight: PropTypes.number }; export default memo(IconTint);
теперь вы можете использовать эту измененную версию следующим образом:
lt;IconTint src={getCustomIcon()} color={isActive ? '#0000ff' : "#b43285"}/gt;