-
Notifications
You must be signed in to change notification settings - Fork 198
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
useImageDimensions #87
Conversation
Have you considered returning an object with |
Doesn't |
Nice idea. Will do. |
React Native for web, what? oO Ok then, it should work I guess. |
This is a nice idea! |
Why did this not produce a canary release? 🤔 Edit: It's because this PR comes from a fork. I enabled the builds to run on PRs from forks, which is great for checking if tests and builds are green, but the canary release doesn't happen because of credentials. I guess it's alright for now, but I created #90 to see if we can enable that. |
src/useImageDimensions.ts
Outdated
* @param source either a remote URL or a local file resource. | ||
* @returns original image width and height. | ||
*/ | ||
function useImageDimensions(source: ImageRequireSource | URISource) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about importing ImageSourcePropType
from react-native
and using that as the type for source
?
function useImageDimensions(source: ImageRequireSource | URISource) { | |
function useImageDimensions(source: ImageSourcePropType) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a lot of redundant properties in ImageSourcePropType too, that are not using in the hook.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any downside to using ImageSourcePropType
, even though it has some more props defined though? 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here is about ImageSourcePropType:
https://reactnative.dev/docs/image#source
This prop can also contain several remote URLs, specified together with their width and height and potentially with scale/other URI arguments. The native side will then choose the best uri to display based on the measured size of the image container.
It means that ImageSourcePropType contains redundant types. No sense to use these types in this hook.
Hey! What is a snack? What do you mean? |
A snack is a way to easily share React Native code, mainly used for testing/demonstrating. Everyone can create one at this site: https://snack.expo.io It would be great if you could create an example that uses your hook there so that we could see it in action! 💪 |
But actually I don't know how this could work, since there is no way for @Greg-Bush to make a canary, right? |
Hey guys! I have made a snack. The Expo snack is working badly with remote images. I don't know the reason. But I have already tested that hook for mobile in the real project locally and it works ok. |
src/useImageDimensions.ts
Outdated
*/ | ||
readonly aspectRatio: number | ||
width: number | ||
height: number |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about making width
and height
readonly
as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unlike 'aspectRatio', actually, these fields are not read-only.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it could be good to mark them as readonly so catch a potential error where the end user accidentally modifies them, since that will be reset each render loop. What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand what do you mean and why do you think that field change will cause anything?
@Greg-Bush would you mind not pressing "Resolve" after answering comments? It becomes very hard for me to find your replies. Thanks! |
Ok, clear |
Hey guys! Is there any decision about that pull request? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are still a few things that I would like to be addressed
src/useImageDimensions.ts
Outdated
* @param source either a remote URL or a local file resource. | ||
* @returns original image width and height. | ||
*/ | ||
function useImageDimensions(source: ImageRequireSource | URISource) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any downside to using ImageSourcePropType
, even though it has some more props defined though? 🤔
@pvinis, the request has long been open. Please, decide here to merge this PR, or not. |
Pushed a commit that typed the return value of the type, reused the return value as to not cause unnecessary re-renders, and cleaned up a bit. Landing now! Thanks for you contribution! 🌟 |
🚀 PR was released in |
Wow! Wtf? Why do you approve your changes and merge them without code review? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Useless change. No sense here at all.
I approved your change, and then I made a few changes as I landed. If you want to I'm sure that @pvinis can review them for me... I didn't think that this was controversial since I've seen it done a lot, and also other maintainers merges minor changes in this repo without someone else approving...
Would you mind elaborating on what part was useless or not making sense? I'd be happy to update... If you are talking about re-using the return value, I do not think that it's useless since it will make sure that e.g. the following code doesn't re-calculate every time: const dimensions = useImageDimensions(...)
const foo = useMemo(() => /* compute with dimensions */, [dimensions])
// ... |
Ok, clear with "result". |
get aspectRatio() { | ||
return this.width / this.height | ||
} | ||
export type Source = ImageRequireSource | URISource |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do you make one more type and export it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If someone wants to build a hook that extends on this hook, it's nice to be able to have one type that represents any input. That way it can easily be used as the input value to a function and just passed on, e.g:
function useHeaderHeight (logo: Source, background: Source): number {
// ...
}
} | ||
export type Source = ImageRequireSource | URISource | ||
|
||
export interface ImageDimensions { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do you also export this one?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If someone wants to build a hook that extends on this hook, it's nice to be able to have one type that represents the return value. That way it can easily be used as the return value to a function and just passed on, e.g:
function useLogoDimensions (): ImageDimensions {
return useImageDimensions(globalSettings.logoImage)
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TypeScript calculates return types automatically, there is no need to mark it manually.
Also, the 'ImageDimensions' name doesn't fully represent the content of this interface. There are 'error' and 'loading' fields. And the sizes themselves are even in a nested property 'dimensions', this field may be called 'ImageDimensions'. The whole object, which contains all of these - not really.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd be open to renaming it ImageDimensionsResult
or something similar...
TypeScript calculates return types automatically, there is no need to mark it manually.
Many style guides mandate that the return type be specified to avoid accidentally not retuning what you intended by clearly stating the intent up front. I think that's a good practice 👍
} catch (error) { | ||
setResult({error, loading: false}) | ||
} | ||
}, [source]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A question here: if the source
is an object, wouldn't it be changed every render, triggering the warning: Maximum update depth exceeded. This can happen when a component calls setState inside useEffect, but useEffect either doesn't have a dependency array, or **one of the dependencies changes on every render.**
? This is because useEffect
hook does shallow comparison, not deep comparison. @Greg-Bush and @LinusU
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It depends on how you pass in the source
, as long as the same object is being passed each render cycle it will not trigger the useEffect
to re-run. The one case I can see would be problematic is if people pass the url as such:
useImageDimensions({ uri: 'https://...' })
We could help with this by doing something like:
- }, [source])
+ }, [source?.uri ?? source])
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@LinusU Yes. That would definitely do the trick. 👍 👍 👍
Summary
This hook will solve the problem when you need to know the original image dimensions or aspect ratio for some complicated markup based on that image. And you might don't know what kind that image will be like: an asset or remote.
Depending on the "source" parameter type it uses one of the following methods:
https://reactnative.dev/docs/image/#resolveassetsource
https://reactnative.dev/docs/image/#getsize
Test Plan
Usage example in readme
Compatibility
Checklist
README.md