использование элемента HTML в качестве элемента JSX - PullRequest
0 голосов
/ 20 апреля 2019

Цель состоит в том, чтобы показать 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 /> таким образом с помощью реквизита.

Я пытался сделать это двумя другими способами

  1. Объявление такого пользовательского 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>'.

И я также погуглил все ошибки, с которыми столкнулся, и попытался их устранить.,Но я никуда не попал.

...