Цель состоит в том, чтобы показать SVG
с анимацией загрузки CSS во время загрузки изображения и заменить его загруженным изображением, когда оно будет сделано.
И в typescript
и react-js
при использованииreact-hooks
.
Что я хочу сделать:
Сохранить изображение в переменной и отобразить его следующим образом.
...
const [Imgthw, setImgthw] = useState<SVG | imgg>(LoadingSVG);
// LoadingSVG is an svg
...
return (
<Imgthw className="svg-loading"/>
)
Где,
SVG
- это тип ReactComponent
при импорте файла SVG.
ìmgJSX
- это тип <img/>
в jsx, равный JSX.IntrinsicElements.img
И Imgthw
имеет тип SVG | imgJSX
Где SVG
определяется как
export type SVG = FunctionComponent<SVGProps<SVGSVGElement>>;
И я попытался imgJSX
как
type imgJSX = JSX.IntrinsicElements.img;
Но ошибка была
Namespace 'global.JSX' has no exported member 'IntrinsicElements'
, так как IntrinsicElements не экспортируется в react/index.d.ts
Поэтому я взял прямое определение из index.d.ts
, которое было
export type imgJSX = React.DetailedHTMLProps<React.ImgHTMLAttributes<HTMLImageElement>, HTMLImageElement>;
svg может быть загружен с использованием последней функции реакции ReactComponent
.
Пример:
import { ReactComponent as LoadingSVG } from "../../assets/loading.svg";
т.е. вместо выполнения
return (
<img src="something.svg"/>
)
Это делаетthis
return (
<svg> /* content of the svg file */ </svg>
)
и для рендеринга SVG я надеваюне хочу использовать тег img
, а вместо этого тег svg
напрямую.т.е. я хочу сделать это способом ReactComponent
, о котором я упоминал выше.
Теперь я использую логику img.onloadend
, чтобы установить переменную следующим образом
const [Imgthw, setImgthw] = useState<SVG | imgg>(LoadingSVG);
useEffect(()=>{
const img = new Image();
img.src = audio.src;
img.onloadend = ()=>{
// remove loading class
setImgthw(img);
};
}, []); // no dependencies i.e. just once which resembles componentDidMount
Теперьошибки:
1.
Type 'HTMLImageElement' is not assignable to type 'DetailedHTMLProps<ImgHTMLAttributes<HTMLImageElement>, HTMLImageElement>'
Где используется setImgthw(img);
.
2.
JSX element type 'Imgthw' does not have any construct or call signatures.
В <Imgthw className="svg-loading"/>
.
Так что мне нужно 1. Найти способ конвертировать изображение типа HTMLImageElement
в imgJSX
.2. Для рендеринга <Imagethw />
таким образом с помощью реквизита.
Я пытался сделать это двумя другими способами
- Объявление такого пользовательского JSX.IntrinsicElement, как указано в официальноммашинописная документация jsx здесь .
declare global {
namespace JSX {
interface IntrinsicElements {
imgS: SVG | imgg;
}
}
};
И используя его как <imgS />
, но нигде не смог получить
Не делать этого, сохраняя компонент в переменной, но с множеством вложенных условий if-else, что делает его кодом для спагетти.
как
...
const [isloading, setIsloading] = useState(true);
...
useEffect(()=>{
const img = new Image();
img.src = imagedata.src;
img.onloadended = ()=>{
setIsloading(false);
}
}, [imagedata.src]);
...
return (
<>
{
imagedata && imagedata.src ?
{
(()=>{
return (isloading) ? <LoadingSVG /> : <img src={imagedata.src}/>
})
} :
<PlaceHolderSVG /> {/* if the image is undefined from the back-end*/}
}
</>
)
Это единственныйработает, но браузер загружает изображение дважды.И я все равно не использую здесь машинопись.
Поэтому я хочу, чтобы существующее изображение из img = new Image()
было напрямую использовано в методе рендеринга.
Редактировать: я пробовал преобразование типоввот так
setImgthw(img as imgJSX);
Но это не конвертируемо.
Ошибка
Type 'HTMLImageElement' is not comparable to type 'ImgHTMLAttributes<HTMLImageElement>'.
И я также погуглил все ошибки, с которыми столкнулся, и попытался их устранить.,Но я никуда не попал.