-
Notifications
You must be signed in to change notification settings - Fork 14
[add] Image source headers handling #11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 5 commits
059ab04
4e6daca
8f4d952
1e54c64
93df02a
7353183
bb25c15
1f393c4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,6 +8,7 @@ | |
* @flow | ||
*/ | ||
|
||
import type { ImageSource, LoadRequest } from '../../modules/ImageLoader'; | ||
import type { ImageProps } from './types'; | ||
|
||
import * as React from 'react'; | ||
|
@@ -146,6 +147,23 @@ function resolveAssetUri(source): ?string { | |
return uri; | ||
} | ||
|
||
function raiseOnErrorEvent(uri, { onError, onLoadEnd }) { | ||
if (onError) { | ||
onError({ | ||
nativeEvent: { | ||
error: `Failed to load resource ${uri} (404)` | ||
} | ||
}); | ||
} | ||
if (onLoadEnd) onLoadEnd(); | ||
} | ||
|
||
function hasSourceDiff(a: ImageSource, b: ImageSource) { | ||
return ( | ||
a.uri !== b.uri || JSON.stringify(a.headers) !== JSON.stringify(b.headers) | ||
Beamanator marked this conversation as resolved.
Show resolved
Hide resolved
|
||
); | ||
} | ||
|
||
interface ImageStatics { | ||
getSize: ( | ||
uri: string, | ||
|
@@ -158,10 +176,12 @@ interface ImageStatics { | |
) => Promise<{| [uri: string]: 'disk/memory' |}>; | ||
} | ||
|
||
const Image: React.AbstractComponent< | ||
type ImageComponent = React.AbstractComponent< | ||
ImageProps, | ||
React.ElementRef<typeof View> | ||
> = React.forwardRef((props, ref) => { | ||
>; | ||
|
||
const BaseImage: ImageComponent = React.forwardRef((props, ref) => { | ||
const { | ||
accessibilityLabel, | ||
blurRadius, | ||
|
@@ -279,16 +299,7 @@ const Image: React.AbstractComponent< | |
}, | ||
function error() { | ||
updateState(ERRORED); | ||
if (onError) { | ||
onError({ | ||
nativeEvent: { | ||
error: `Failed to load resource ${uri} (404)` | ||
} | ||
}); | ||
} | ||
if (onLoadEnd) { | ||
onLoadEnd(); | ||
} | ||
Beamanator marked this conversation as resolved.
Show resolved
Hide resolved
|
||
raiseOnErrorEvent(uri, { onError, onLoadEnd }); | ||
} | ||
); | ||
} | ||
|
@@ -332,14 +343,67 @@ const Image: React.AbstractComponent< | |
); | ||
}); | ||
|
||
Image.displayName = 'Image'; | ||
BaseImage.displayName = 'Image'; | ||
|
||
/** | ||
* This component handles specifically loading an image source with headers | ||
* default source is never loaded using headers | ||
*/ | ||
const ImageWithHeaders: ImageComponent = React.forwardRef((props, ref) => { | ||
// $FlowIgnore | ||
const nextSource: ImageSource = props.source; | ||
const [blobUri, setBlobUri] = React.useState(''); | ||
const request = React.useRef<LoadRequest>({ | ||
cancel: () => {}, | ||
source: { uri: '', headers: {} }, | ||
promise: Promise.resolve('') | ||
}); | ||
Comment on lines
+356
to
+360
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
const { onError, onLoadStart, onLoadEnd } = props; | ||
|
||
React.useEffect(() => { | ||
if (!hasSourceDiff(nextSource, request.current.source)) return; | ||
kidroca marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
// When source changes we want to clean up any old/running requests | ||
request.current.cancel(); | ||
|
||
if (onLoadStart) onLoadStart(); | ||
kidroca marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
request.current = ImageLoader.loadWithHeaders(nextSource); | ||
Beamanator marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
request.current.promise | ||
.then((uri) => setBlobUri(uri)) | ||
.catch(() => | ||
raiseOnErrorEvent(request.current.source.uri, { onError, onLoadEnd }) | ||
kidroca marked this conversation as resolved.
Show resolved
Hide resolved
|
||
); | ||
}, [nextSource, onLoadStart, onError, onLoadEnd]); | ||
|
||
// Cancel any request on unmount | ||
React.useEffect(() => request.current.cancel, []); | ||
|
||
const propsToPass = { | ||
...props, | ||
// Omit `onLoadStart` because we trigger it in the current scope | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not too sure what this comment means. Is there a different way to say this? I think it's something like - the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it's more like: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Now that I look at it I see it's confusing - it's like Alex said - loading starts inside There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok cool I think we are all saying the same thing -
kidroca marked this conversation as resolved.
Show resolved
Hide resolved
|
||
onLoadStart: undefined, | ||
// Until the current component resolves the request (using headers) | ||
kidroca marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// we skip forwarding the source so the base component doesn't attempt | ||
// to load the original source | ||
source: blobUri ? { ...nextSource, uri: blobUri } : undefined | ||
}; | ||
|
||
return <BaseImage ref={ref} {...propsToPass} />; | ||
}); | ||
|
||
// $FlowIgnore: This is the correct type, but casting makes it unhappy since the variables aren't defined yet | ||
const ImageWithStatics = (Image: React.AbstractComponent< | ||
ImageProps, | ||
React.ElementRef<typeof View> | ||
> & | ||
ImageStatics); | ||
const ImageWithStatics: ImageComponent & ImageStatics = React.forwardRef( | ||
(props, ref) => { | ||
if (props.source && props.source.headers) { | ||
return <ImageWithHeaders ref={ref} {...props} />; | ||
} | ||
|
||
return <BaseImage ref={ref} {...props} />; | ||
} | ||
); | ||
|
||
ImageWithStatics.getSize = function (uri, success, failure) { | ||
ImageLoader.getSize(uri, success, failure); | ||
|
Uh oh!
There was an error while loading. Please reload this page.