Я работаю над проблемой, при которой изображение SVG необходимо загрузить с URL-адреса (AWS S3) в компонент реакции. Я могу успешно отображать и загружать изображение с помощью встроенного SVG-компонента реакции из локального файла. Однако файлы svg необходимо загружать прямо из корзины S3, импорт JS svg не работает с URL-адресами.
Итак, я пытаюсь найти лучшее альтернативное решение для этого?
Чтобы импортировать встроенный SVG как компонент React из URL-адреса, мне удалось загрузить SVG из локального встроенного файла, но не из URL-адреса.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Вы должны получить изображение svg и вставить его в html
const SVG_URL = url = 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/106114/tiger.svg';
class Svg extends React.Component {
state = {
svg: null,
loading: false,
}
componentDidMount() {
fetch(this.props.url)
.then(res => res.text())
.then(text => this.setState({ svg: text }));
}
render() {
const { loading, svg } = this.state;
if (loading) {
return <div className = "spinner"/>;
} else if (!svg) {
return <div className = "error"/>
}
return <div dangerouslySetInnerHTML = {{ __html: this.state.svg}}/>;
}
}
ReactDOM.render(
<Svg url='https://s3-us-west-2.amazonaws.com/s.cdpn.io/106114/tiger.svg' />,
document.querySelector("#app")
);
Вы можете отредактировать пример здесь https://jsfiddle.net/anu6x3bk/
React не рекомендует использовать dangerouslySetInnerHTML, поэтому вам следует использовать какой-нибудь пакет, например svg-inline-react.
Нет необходимости во внешнем пакете, так как svg-inline-react также использует dangerouslySetInnerHTML: github.com/sairion/svg-inline-react/blob/master/src/index.js
@ivnkld ответ указал мне правильное направление, спасибо! И для гуглеров, таких как я, вот реализация того же подхода с хуками:
import React, { useEffect, useState } from 'react';
const SvgInline = props => {
const [svg, setSvg] = useState(null);
const [isLoaded, setIsLoaded] = useState(false);
const [isErrored, setIsErrored] = useState(false);
useEffect(() => {
fetch(props.url)
.then(res => res.text())
.then(setSvg)
.catch(setIsErrored)
.then(() => setIsLoaded(true))
}, [props.url]);
return (
<div
className = {`svgInline svgInline--${isLoaded ? 'loaded' : 'loading'} ${isErrored ? 'svgInline--errored' : ''}`}
dangerouslySetInnerHTML = {{ __html: svg }}
/>
);
}
Для тех, кто не хочет использовать опасноSetInnerHTML, проверьте следующий пример. Как только мы получим svg как текст из api, мы будем использовать DOMParser для преобразования текста в объект Документ. Затем мы будем использовать React.createElement для рендеринга изображения (или) значка.
// utils/convertDocEleToReact.js
import { createElement } from "react";
const innerFunction = (element, props) => {
const tagName = element.tagName;
let _props = props || {};
for(let i = 0; i < element.attributes.length; i++){
_props[element.attributes[i].nodeName] = element.attributes[i].nodeValue;
}
let children = Array.from(element.children).map(item => innerFunction(item));
return createElement(tagName, _props, children);
};
export const convertDocEleToReact = (element, props) => {
try{
return innerFunction(element, props);
}
catch(ex){
return createElement("span", {}, "Error loading svg image");
}
};
// components/SVGUrl.js
import React from "react";
import { convertDocEleToReact } from "./utils/convertDocEleToReact";
export const SVGUrl = ({ ...props }) => {
const [ Comp, setComp ] = useState(null);
const [loading, setLoading] = useState(false);
useEffect(_ => {
setLoading(true);
fetch(/** svg url */)
.then(res => res.text())
.then(res => {
const domParser = new DOMParser();
const ele = domParser.parseFromString(res, "image/svg+xml");
setComp(convertDocEleToReact(ele.documentElement, props));
setLoading(false);
});
}, []);
return loading ? "..." : Comp;
};
Не уверен, что вы имеете в виду ... Если изображение видно в сети, вы должны иметь возможность добавить его в тег изображения, верно? Это как любой другой html-документ. Или это проблема при компиляции?