Skip to content
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

shared element transition #75

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
Open

Conversation

Nnanyielugo
Copy link
Collaborator

No description provided.

@Nnanyielugo Nnanyielugo marked this pull request as draft January 25, 2023 22:31
@Nnanyielugo Nnanyielugo marked this pull request as ready for review January 27, 2023 12:34
@@ -248,17 +248,17 @@ const DiveSite: FunctionComponent<DiveSiteProps> = ({ navigation, route }) => {
<ScrollView
style={styles.scrollContainer}
showsVerticalScrollIndicator={false}>
<SharedElement id={`item.${navObjectSpot.id}.image`}>
<SharedElement id={`item.${(navObjectSpot as Spot).id}.image`}>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rather than re-casting this here all the time, we should re-cast it at the top of the file when it's initialized

Copy link
Collaborator

@mjmayank mjmayank Jan 27, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

doing this is basically just ignoring the type warnings. if navObjectSpot is sometimes optional we need to add logic that ensures that it's fetched/defined

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually can't typecast when initialised (linter will bleat) because it is an optional navigation param. I can use a question mark for the values that don't need typecasting and typecast the only one that needs it.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really. If you check line 227, you'd see where I handled the case where navObjectSpot is undefined. Else navigating to DiveSpot from search would break the app.

I deliberately made it optional because I know not all redirects to that page will pass along the navObjectSpot.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah the compiler is correct that this value isn't guaranteed to exist. so we need to create code patterns that ensure it exists, like adding the question mark or checking for null some other way. otherwise for example if the user enters this screen from a deeplink (where they would have just the beach ID and not the navObjectSpot, then it could result in an error/crash)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. Except I purposely told the compiler that that value might not exist. It is reading from a Navigator type object for that page that I defined, and deliberately made optional.

If I change that value and make the compiler thing it will always exist, that error will disappear.

And I've already handled the case for when the object doesn't exist (see line 227 of the same file. mentioned in my previous reply). Deeplink is not the only use case for this. It also happens when the user navigates from explore screen search results. those typically don't carry beach objects with them.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you may be right, but ill need to read the full code more closely when i get time later today.

in general having to cast things this way isn't ideal and there is a better way to do it that still allows the compiler to help catch future bugs, which is why i'm skeptical

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just to elaborate, generally the only times you want to cast are when things are at the time something is coming in from an external interface, and you know it's guaranteed to exist otherwise something else has gone wrong (eg an API response with a specific format).

In this case the data could be coming from an external interface (eg deeplink), but the correct typing is still optional as you stated, since that data isn't guaranteed to exist. So then for the rest of the code we shouldn't be doing typecasting and instead working with the compiler to ensure the values exist.

@@ -152,7 +152,7 @@ const DiveSite: FunctionComponent<DiveSiteProps> = ({ navigation, route }) => {

// just make call to fetch beach if no images, since we're only calling this hook once now
dispatch(handleFetchDiveSite(currentSpotId));
}, [currentSpotId]); // eslint-disable-line react-hooks/exhaustive-deps
}, []); // eslint-disable-line react-hooks/exhaustive-deps
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why did you change this?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, that was a mistake. Was trying to fix a very strange bug infinity loop bug so I was fiddling with the dependenncy list to try to understand where it came from. Reinstalled now.

@@ -0,0 +1,367 @@
import React from 'react';
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i don't think duplicating all this code feels like the correct way to handle this logic. at the very least, we need to them break the whole screen up into smaller components that are imported into dive site with/without nav object, but otherwise it will get really hard to maintain these separate components as we make other design changes

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes (about breaking the entire screen part). I wasn't sure that the transition would work if the elements it affects are not in the component that it extends with .sharedElements. Maybe I'll try and see what happens.

@@ -82,7 +90,8 @@ const DiveSite: FunctionComponent<DiveSiteProps> = props => {
<TouchableOpacity
activeOpacity={0.8}
onPress={() =>
props.onPressContainer && props.onPressContainer(props.site.id)
props.onPressContainer &&
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: i think we can delete this since it's already checked above

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tried before. Compiler bleated. Decided to leave it alone. Complier is still bleating.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh weird. that's fine then

}, [currentSpotId, dispatch, reviewInState, diveSiteInState, diveSite]);
// just make call to fetch beach if no images, since we're only calling this hook once now
dispatch(handleFetchDiveSite(currentSpotId));
}, [currentSpotId]); // eslint-disable-line react-hooks/exhaustive-deps
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm the old dependencies seem more correct imo. although we could probably avoid fetching the nearby sites too frequently. maybe all these fetches should all be in different effects

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I removed it because I figured that function only needs to run once, when the currentSpotId changes. All of the other dependencies will only trigger re-renders. None of those calls need to happen more than once.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the correct dependency array is [currentSpotId, dispatch, diveSiteInState, diveSite] so you can remove reviewInState. I think otherwise the correct change would be to split these up into separate effects. then you can delete the linter comment, and still only have it run the correct number of times for each fetch

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants