From 2dac11500f4c53566dd0b5e32ba2a1525791b176 Mon Sep 17 00:00:00 2001 From: Robert Fischer Date: Fri, 17 Aug 2018 14:29:20 -0400 Subject: [PATCH 1/7] Ignore yarn.lock and node_modules --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a8669b1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +yarn.lock +node_modules From 96dfc096cecdf9d0d395d12be53379e60ca8e678 Mon Sep 17 00:00:00 2001 From: Robert Fischer Date: Fri, 17 Aug 2018 14:29:55 -0400 Subject: [PATCH 2/7] Add in debug (and supports-color to make it more colorful) --- package.json | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index cbb416b..97486b1 100644 --- a/package.json +++ b/package.json @@ -16,5 +16,11 @@ "react-native", "svg", "image" - ] + ], + "dependencies": { + "debug": "^3.1.0" + }, + "devDependencies": { + "supports-color": "^5.4.0" + } } From 472f50edd0fbfd7c460671bd81233c2ecc649885 Mon Sep 17 00:00:00 2001 From: Robert Fischer Date: Fri, 17 Aug 2018 15:35:31 -0400 Subject: [PATCH 3/7] Add in cancellation; do a bit of code cleanup --- SvgImage.js | 90 ++++++++++++++++++++++++++++++++++------------------ package.json | 4 ++- 2 files changed, 62 insertions(+), 32 deletions(-) diff --git a/SvgImage.js b/SvgImage.js index 964b036..48194f7 100644 --- a/SvgImage.js +++ b/SvgImage.js @@ -1,46 +1,81 @@ // @flow +import PropTypes from 'prop-types'; import React, { Component } from 'react'; -import { View, WebView } from 'react-native'; +import { View, WebView, StyleSheet } from 'react-native'; +import Promise from 'bluebird'; +Promise.config({ cancellation: true }); // Need to explicitly enable this feature const firstHtml = ''; const lastHtml = ''; class SvgImage extends Component { - state = { fetchingUrl: null, svgContent: null }; + + static propTypes = { + source: PropTypes.shape({ + uri: PropTypes.string.isRequired + }).isRequired, + containerStyle: PropTypes.oneOfType([ + PropTypes.instanceOf(StyleSheet).isRequired, + PropTypes.object.isRequired, + ]), + style: PropTypes.oneOfType([ + PropTypes.instanceOf(StyleSheet).isRequired, + PropTypes.object.isRequired, + ]), + } + + state = { + svgContent: null, + fetchingPromise: null, + }; + componentDidMount() { - this.doFetch(this.props); + this.doFetch(); + } + + componentWillUnmount() { + const { fetchingPromise } = this.state || {}; + if(fetchingPromise) fetchingPromise.cancel(); } - componentWillReceiveProps(nextProps) { - this.doFetch(nextProps); + + componentDidUpdate(prevProps) { + const { source:oldSource } = prevProps || {}; + const { uri:oldUri } = oldSource || {}; + const { source:newSource } = this.props || {}; + const { uri:newUri } = newSource || {}; + if(oldUri !== newUri) this.doFetch(); } - doFetch = props => { - let uri = props.source && props.source.uri; + + doFetch() { + const { source } = this.props || {}; + const { uri } = source || {}; if (uri) { if (uri.match(/^data:image\/svg/)) { const index = uri.indexOf(' res.text()) - .then(text => { - this.setState({ fetchingUrl: uri, svgContent: text }); - }) - .catch(err => { - console.error('got error', err); - }); + this.setState(({fetchingPromise:previousFetch}) => ({ fetchingPromise: + Promise.resolve(fetch(uri)) + .call("text") + .then(text => this.setState({ svgContent: text })) + .timeout(1000 * 60, `SVG URI fetch timed out: ${uri}`) + .catch(e => console.error(`Error fetching SVG URI: ${e.message||e}`, {uri, e})) + .return((previousFetch && previousFetch.isPending()) ? previousFetch : null) // Ensure we resolve/cancel previous fetch + })) } } - }; + } + render() { - const props = this.props; - const { svgContent } = this.state; - if (svgContent) { + const props = this.props || {}; + const { svgContent } = this.state || {}; + const hasSvgContent = Boolean(svgContent); return ( - - + { hasSvgContent && + /> } ); - } else { - return ( - - ); - } } } + export default SvgImage; diff --git a/package.json b/package.json index 97486b1..4a39a12 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,9 @@ "image" ], "dependencies": { - "debug": "^3.1.0" + "bluebird": "^3.5.1", + "debug": "^3.1.0", + "prop-types": "^15.6.2" }, "devDependencies": { "supports-color": "^5.4.0" From e3912ca07e90eb4a9905c272d4e955644fdd2651 Mon Sep 17 00:00:00 2001 From: Robert Fischer Date: Fri, 17 Aug 2018 15:49:37 -0400 Subject: [PATCH 4/7] Don't actually need the timeout, because we cancel on unmount --- SvgImage.js | 1 - 1 file changed, 1 deletion(-) diff --git a/SvgImage.js b/SvgImage.js index 48194f7..a85aa82 100644 --- a/SvgImage.js +++ b/SvgImage.js @@ -61,7 +61,6 @@ class SvgImage extends Component { Promise.resolve(fetch(uri)) .call("text") .then(text => this.setState({ svgContent: text })) - .timeout(1000 * 60, `SVG URI fetch timed out: ${uri}`) .catch(e => console.error(`Error fetching SVG URI: ${e.message||e}`, {uri, e})) .return((previousFetch && previousFetch.isPending()) ? previousFetch : null) // Ensure we resolve/cancel previous fetch })) From 479020a53d1fd84d84d9f01d67cc92042069eba1 Mon Sep 17 00:00:00 2001 From: Robert Fischer Date: Fri, 17 Aug 2018 16:14:19 -0400 Subject: [PATCH 5/7] Improvement on the style type --- SvgImage.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/SvgImage.js b/SvgImage.js index a85aa82..bc12038 100644 --- a/SvgImage.js +++ b/SvgImage.js @@ -6,6 +6,12 @@ import { View, WebView, StyleSheet } from 'react-native'; import Promise from 'bluebird'; Promise.config({ cancellation: true }); // Need to explicitly enable this feature +// Calculate this once +const styleType = PropTypes.oneOfType([ + PropTypes.instanceOf(StyleSheet.create({display:"none"}).constructor).isRequired, + PropTypes.object.isRequired, +]); + const firstHtml = ''; const lastHtml = ''; @@ -16,14 +22,8 @@ class SvgImage extends Component { source: PropTypes.shape({ uri: PropTypes.string.isRequired }).isRequired, - containerStyle: PropTypes.oneOfType([ - PropTypes.instanceOf(StyleSheet).isRequired, - PropTypes.object.isRequired, - ]), - style: PropTypes.oneOfType([ - PropTypes.instanceOf(StyleSheet).isRequired, - PropTypes.object.isRequired, - ]), + containerStyle: styleType, + style: styleType, } state = { From f7b707c96d788f00884fefa0c033a89d440e4187 Mon Sep 17 00:00:00 2001 From: Robert Fischer Date: Fri, 17 Aug 2018 16:18:21 -0400 Subject: [PATCH 6/7] Remove the StyleSheet check; just didn't work --- SvgImage.js | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/SvgImage.js b/SvgImage.js index bc12038..0065931 100644 --- a/SvgImage.js +++ b/SvgImage.js @@ -2,15 +2,12 @@ import PropTypes from 'prop-types'; import React, { Component } from 'react'; -import { View, WebView, StyleSheet } from 'react-native'; +import { View, WebView } from 'react-native'; import Promise from 'bluebird'; Promise.config({ cancellation: true }); // Need to explicitly enable this feature -// Calculate this once -const styleType = PropTypes.oneOfType([ - PropTypes.instanceOf(StyleSheet.create({display:"none"}).constructor).isRequired, - PropTypes.object.isRequired, -]); +// TODO Make this something more precise oneOf(object,_?_), where _?_ is the type returned by `StyleSheet.create`. +const styleType = PropTypes.object.isRequired; const firstHtml = ''; From c712a3714d0fa79a717bab53fcd8907a496ee0eb Mon Sep 17 00:00:00 2001 From: Robert Fischer Date: Fri, 17 Aug 2018 17:17:46 -0400 Subject: [PATCH 7/7] Don't require the style objects --- SvgImage.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SvgImage.js b/SvgImage.js index 0065931..81fd30e 100644 --- a/SvgImage.js +++ b/SvgImage.js @@ -7,7 +7,7 @@ import Promise from 'bluebird'; Promise.config({ cancellation: true }); // Need to explicitly enable this feature // TODO Make this something more precise oneOf(object,_?_), where _?_ is the type returned by `StyleSheet.create`. -const styleType = PropTypes.object.isRequired; +const styleType = PropTypes.object; const firstHtml = '';