mirror of
https://github.com/zoriya/react-native-svg.git
synced 2026-05-28 04:55:12 +00:00
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:
@@ -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 />;
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
@@ -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
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user