Prevents SvgUri crashes when uri is invalid and adds fallback prop (#2071)

SvgUri component crashes an app when uri with SVG returns html or some other content instead of valid SVG.
This change prevents those crashes and adds fallback property of JSX type which is rendered instead of corrupted SVG.
This commit is contained in:
PiotrWszolek
2023-07-06 14:21:20 +02:00
committed by GitHub
parent 7983ad2ca6
commit e04a159b46
4 changed files with 67 additions and 10 deletions
+1
View File
@@ -8,6 +8,7 @@ import Test1813 from './src/Test1813';
import Test1845 from './src/Test1845';
import Test2080 from './src/Test2080';
import PointerEventsBoxNone from './src/PointerEventsBoxNone';
import Test2071 from './src/Test2071';
export default function App() {
return <ColorTest />;
+46
View File
@@ -0,0 +1,46 @@
import * as React from 'react';
import {View} from 'react-native';
import Svg, {Circle, SvgXml} from 'react-native-svg';
export default function App() {
const svgXmlWithTransform = `<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" width="100" height="300" viewBox="0 0 100 100" transform="scale(1 -1)">
<circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red" />
</svg>`;
const svgXmlWithEmptyStyle = `<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100">
<circle style=" " cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red" />
</svg>`;
const svgg = `
<svg width="400" height="200">
<polygon points="100 100, 180 100, 140 180" fill="black"></polygon>
<polygon points="100 100, 180 100, 140 180" fill="red" transform="translate(0, 280), scale(1, -1)"></polygon>
</svg>
`;
const xmll = `en.wikipedia.org/wiki/File:Vector-based_example.svg`;
return (
<View style={{flex: 1}}>
<SvgXml
onError={() => {}}
xml={xmll}
fallback={
<Svg
width={100}
height={100}
viewBox="0 0 100 100"
transform={[{scaleX: 1}, {scaleY: -1}]}>
<Circle
cx={50}
cy={50}
r={40}
stroke="black"
strokeWidth={3}
fill="red"
/>
</Svg>
}
/>
</View>
);
}
+4 -1
View File
@@ -122,11 +122,13 @@ export default function TestComponent() {
Both `SvgUri` and `SvgCssUri` log errors to the console, but otherwise ignore them.
You can set property `onError` if you want to handle errors such as resource not
existing in a different way.
existing in a different way and `fallback` if you want to render another component
instead in such case.
```jsx
import * as React from 'react';
import { SvgUri } from 'react-native-svg';
import { SvgFallback } from './components/SvgFallback';
export default () => {
const [uri, setUri] = React.useState(
@@ -140,6 +142,7 @@ export default () => {
width="100%"
height="100%"
uri={uri}
fallback={<SvgFallback />}
/>
);
};
+16 -9
View File
@@ -81,6 +81,7 @@ export type AdditionalProps = {
onError?: (error: Error) => void;
override?: Object;
onLoad?: () => void;
fallback?: JSX.Element;
};
export type UriProps = SvgProps & { uri: string | null } & AdditionalProps;
@@ -106,17 +107,17 @@ export function SvgAst({ ast, override }: AstProps) {
export const err = console.error.bind(console);
export function SvgXml(props: XmlProps) {
const { onError = err, xml, override } = props;
const ast = useMemo<JsxAST | null>(
() => (xml !== null ? parse(xml) : null),
[xml],
);
const { onError = err, xml, override, fallback } = props;
try {
const ast = useMemo<JsxAST | null>(
() => (xml !== null ? parse(xml) : null),
[xml],
);
return <SvgAst ast={ast} override={override || props} />;
} catch (error) {
onError(error);
return null;
return fallback ?? null;
}
}
@@ -129,19 +130,25 @@ export async function fetchText(uri: string) {
}
export function SvgUri(props: UriProps) {
const { onError = err, uri, onLoad } = props;
const { onError = err, uri, onLoad, fallback } = props;
const [xml, setXml] = useState<string | null>(null);
const [isError, setIsError] = useState(false);
useEffect(() => {
uri
? fetchText(uri)
.then((data) => {
setXml(data);
isError && setIsError(false);
onLoad?.();
})
.catch(onError)
.catch((e) => {
onError(e)
setIsError(true);
})
: setXml(null);
}, [onError, uri, onLoad]);
return <SvgXml xml={xml} override={props} />;
if (isError) return fallback ?? null;
return <SvgXml xml={xml} override={props} fallback={fallback} />;
}
// Extending Component is required for Animated support.