Skip to content
This repository has been archived by the owner on Oct 1, 2024. It is now read-only.

[react-hooks] initialize Media hooks with correct matches value #2809

Merged
merged 1 commit into from
Jul 15, 2024

Conversation

melnikov-s
Copy link
Contributor

Description

re-opening of #2341

Description of original issue can be found there.

Forcing SSR support causes additional renders and potential layout shifts. To support CSR applications useMedia now sets the real value on initial render. For continued SSR support new options are provided to set the default value.

This is inline with similar hooks such as: https://usehooks-ts.com/react-hook/use-media-query

Fixes (issue #)

Copy link
Member

@vividviolet vividviolet left a comment

Choose a reason for hiding this comment

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

Just a small suggestion

},
) => {
const [match, setMatch] = useState(() =>
ssr ? Boolean(ssrValue) : window.matchMedia(query).matches,
Copy link
Member

Choose a reason for hiding this comment

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

Should we just do this?

Suggested change
ssr ? Boolean(ssrValue) : window.matchMedia(query).matches,
ssrValue !== undefined ? Boolean(ssrValue) : window.matchMedia(query).matches,

Copy link
Contributor Author

Choose a reason for hiding this comment

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

good call, I'll make that change

@melnikov-s
Copy link
Contributor Author

/snapit

1 similar comment
@melnikov-s
Copy link
Contributor Author

/snapit

@melnikov-s melnikov-s merged commit 5546b1d into main Jul 15, 2024
5 checks passed
@melnikov-s melnikov-s deleted the media-match-initial-render branch July 15, 2024 17:49
@jas7457
Copy link
Contributor

jas7457 commented Jul 18, 2024

I came across this when I saw there was a new major version. Won't this cause more issues than just simple SSR / hydration issues? Using window.matchMedia if initialValue isn't defined won't simply cause a hydration issue, it would throw on the server.

I'm not sure that changing something which, at worse before was a unnecessary render, to something which will start to throw by default, is a good idea.

@melnikov-s what do you think?

@melnikov-s
Copy link
Contributor Author

@melnikov-s what do you think?

Yes, it will throw and initialValue now needs to be provided if you want to continue to support SSR thus the major version bump.

From my perspective throwing might even be preferable as it provides a more immediate feedback instead of a hydration mismatch which could be missed. Making the consumer aware that they now need to provide an initialValue

We could throw with a better error msg if initialValue === undefined && typeof window === 'undefined though

@jas7457
Copy link
Contributor

jas7457 commented Jul 18, 2024

If initialValue needs to be provided, it shouldn't be marked as an optional property. We should get TypeScript errors, not runtime errors, as depending on the way or order in which a route is rendered would determine if you'd see this error in the runtime or not.

You mentioned you modeled this off of other popular hooks like useMediaQuery, but you can see that they provide defaults for their values and they check if they're on the server or not.

image

I think we've enabled too many footguns to say it is both optional and there is no check if that we're not on the server for something like this.

@melnikov-s
Copy link
Contributor Author

If initialValue needs to be provided, it shouldn't be marked as an optional property.

It only needs to be provided for SSR, for CSR it does not. Typescript has no awareness of this so can't really enforce that there.

I don't think there's a prefect approach here, they all have their cons. Though if you're doing SSR you want to have a consistent value during hydration and throwing an error can be seen as a forcing function of that.

That being said, I don't have a firm opinion on this. We can add the IS_SERVER check if there's consensus that it's better to have a hydration mismatch then to throw when we can't enforce this with types.

@vividviolet
Copy link
Member

I would prefer to keep things simple if possible as this library is only being used by Web which no longer does SSR. Updating to initialValue === undefined && typeof window === 'undefined makes sense to me. typeof window === 'undefined is essentially the IS_SERVER check.

I think it's fine to make a breaking change with a breaking change log calling out that the initialValue is required if you are using it with server side rendering.

@jas7457 the example you showed has default the value to false which doesn't work for client side rendering. If we make the initial value mandatory then the consumer would have to do window. matchMedia to set the initial value.

@jas7457
Copy link
Contributor

jas7457 commented Jul 18, 2024

I think it's fine to make a breaking change with a breaking change log calling out that the initialValue is required if you are using it with server side rendering.

I would typically agree, that's what major changes are for, after all. However, the item in the change log simply says "#2809 5546b1d Thanks @​melnikov-s! - Media hooks initialized with correct matches value" - I don't see any mention about needing to make changes if you use SSR.

Remix is our blessed approach to Shopify apps now, which is a SSR library. I think that our default for this hook should be that it works for our blessed approach.

Updating to initialValue === undefined && typeof window === 'undefined makes sense to me.

Yes, this is really all we need, but I think you mean !== instead of ===

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

Successfully merging this pull request may close these issues.

4 participants