You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Check out this [post](https://ayhota.com/blog/articles/responsive-react-components) to learn more about the motivation behind Responsive System.
7
+
## Motivation
6
8
7
-
## Upgrading?
9
+
CSS media queries are great for dynamically changing styles based on screen size, but sometimes you need values in your JavaScript code to respond to screen-size changes as well.
8
10
9
-
Jump to the [Changelog](#changelog) for information about breaking changes and recommendations around upgrading.
11
+
Check out [this blog post](https://ayhota.com/blog/articles/responsive-react-components) for a deeper dive into the problem space!
10
12
11
13
## What does it look like?
12
14
15
+
You give us a list of screen size boundaries where things might need to change ("breakpoints").
16
+
17
+
```js
18
+
constbreakpoints= {
19
+
// name them whatever you want
20
+
small:768, // any screen up to 768px is called "small"
21
+
medium:960, // from 769 to 960 it's "medium"
22
+
large:1280, // from 960 to 1280 it's "large"
23
+
xl:Infinity, // anything larger than 1280 is "xl"
24
+
// have as many as you'd like
25
+
};
26
+
```
27
+
28
+
and we give you back a hook for when you need a value to be responsive.
29
+
13
30
```jsx
14
31
constMyResponsiveComponent() {
15
-
constmessage= useResponsiveValue<string>("Your screen is big", { onSmallScreens:"Your screen is small" });
1.[Define your breakpoints in JS](#1-define-your-breakpoints-in-js)
33
-
2.[Generate your custom Responsive System with `createResponsiveSystem`](#2-generate-your-custom-responsive-system-with-createresponsivesystem)
34
-
3.[Render the ScreenClassProvider near the root of your app](#3-render-the-screenclassprovider-near-the-root-of-your-app)
55
+
1.[Define your breakpoints](#1-define-your-breakpoints)
56
+
2.[Initialize the system](#2-initialize-the-system)
57
+
3.[Render the Provider](#3-render-the-provider)
35
58
4.[Make your components responsive](#4-make-your-components-responsive)
36
59
37
-
### 1. Define your breakpoints in JS
60
+
### 1. Define your breakpoints
38
61
39
-
To keep things organized, folks often create a new file called `responsiveSystem.js/ts` where they'll configure Responsive System.
62
+
> Tip: to keep things organized, folks often create a new file called `responsiveSystem.js/ts` where they'll configure Responsive System.
40
63
41
-
But, no matter where you choose to keep the configuration, the first step is to define your breakpoints in JS:
64
+
The first step is to define your breakpoints in JS:
42
65
43
66
```js
44
67
/* responsiveSystem.js/ts */
@@ -51,11 +74,9 @@ const breakpoints = {
51
74
};
52
75
```
53
76
54
-
The values that you provide are the "maximum pixel-widths" for that screenclass. In order to make sure that all possible screen pixel-sizes are handled, there should be exactly one screen class with a value of `Infinity` which tells us that there is no maximum pixel-width for that screen class.
77
+
The values that you provide are the maximum pixel-widths for each named screen-size range ("screen class"). In order to make sure that all possible screen sizes are covered, there should be exactly one screen class with a maximum pixel-width of `Infinity`.
55
78
56
-
### 2. Generate your custom Responsive System with `createResponsiveSystem`
57
-
58
-
Here, you'll configure Responsive System with your breakpoints.
We call `createResponsiveSystem` with our own custom breakpoints, and we get back a `ScreenClassProvider` (keeps track of the current screen class), and a hook called `useResponsiveValue` (creates a value that changes based on the screen class).
75
98
76
-
We're calling `createResponsiveSystem` with our own custom breakpoints, and we get back a `ScreenClassProvider` (keeps track of the current screen class), and a hook called `useResponsiveValue` (creates a value that changes based on the screen class). Then, we export everything so that we can import it across our app.
99
+
### 3. Render the Provider
77
100
78
-
### 3. Render the ScreenClassProvider near the root of your app
101
+
Somewhere near the root of your app, add the `ScreenClassProvider`. This component keeps track of the screen size and provides it to the rest of the app.
The first param is the default value (used when there are no applicable overrides) and the second param specifies the overrides. Check out the [Cascading](#cascading) section to see how you can customize the behavior of these overrides.
By default, Responsive System overrides do not cascade, which is to say: if you add an override for screen class `X`, those overrides will only be applied when the user's browser/device matches screen class `X`. But in some cases, you might want to apply overrides on `X` and also anything larger/smaller than `X`.
137
+
By default, Responsive System overrides do not cascade, which is to say: if you add an override for screen class `X`, those overrides will only be applied when the user's screen matches `X`_exactly_. But in some cases, you might want to apply overrides on `X` and also anything larger/smaller than `X`.
114
138
115
139
This is where `cascadeMode` comes in.
116
140
@@ -121,10 +145,10 @@ This is where `cascadeMode` comes in.
121
145
This is the default configuration. There is no implicit overriding in this mode.
Server-Side rendering is a bit tricky because we don't have access to the user's device to measure their screen. Because we can't automatically determine the proper screen class during SSR, you must "manually" provide an `initialScreenClass` for Responsive System to render.
208
+
Server-Side rendering is a bit tricky because when we're on the server we don't have direct access to the user's screen. Since we can't determine the screen class automatically, you must "manually" provide an `initialScreenClass` for Responsive System to render.
@@ -194,32 +222,30 @@ This is the easiest approach. If you don't SSR, then you don't have to worry abo
194
222
195
223
### Client-Only Components
196
224
197
-
You can render some placeholder content (like a spinner/skeleton/glimmer) during SSR and then render the correct content once the code gets to the client. Showing a loading experience is better than showing an incorrect layout and then shifting it.
225
+
You can render some placeholder content (like a spinner/skeleton/glimmer) during SSR and then render the correct content once the code gets to the client. Showing a loading experience is better than showing incorrect/broken content and then shifting it.
198
226
199
-
Here's a quick implementation that you could use to render a placeholder on the server:
227
+
Here's a quick implementation that shows how to detect whether you're rendering on the server or the client.
// will return `placeholder` on the server and `children` on the client
209
-
returnisOnClient.current? children : placeholder;
235
+
return isOnClient ? children : placeholder;
210
236
}
211
-
// usage
212
-
<ClientOnly placeholder={<PlaceholderContent />}>
213
-
<ResponsiveComponent />
214
-
</ClientOnly>;
215
237
```
216
238
239
+
If you're using this pattern, I actually recommend adapting it to use React Context so that you can determine `isOnClient` once and provide that context for the lifetime of the app vs having every new component start off as `false` only to immediately switch to `true`.
240
+
217
241
### Smart Server
218
242
243
+
You can try to do some clever things with your server in order to improve your chances of guessing the correct initial screen class.
244
+
219
245
This route is tricky, but if you want to try it, here are some ideas:
220
246
221
-
-At a minimum you can check the User-Agent Request header to get an idea of what type of device is being used (mobile vs laptop/desktop) and use that info to make an educated guess.
222
-
- If your user is navigating from page to page in your app and you control the links, you could append width and height query params to each request before it goes out. The first page they hit wouldn't have the query params, but all subsequent pages would. And it's technically possible for someone to resize their screen after they click a link, so it's not bulletproof.
247
+
-You can check the User-Agent Request header to get an idea of what type of device is being used (mobile vs laptop/desktop) and use that info to make an educated guess. Check out [ua-parser-js](https://www.npmjs.com/package/ua-parser-js) for parsing user agents on Node servers.
248
+
- If your user is navigating from page to page in your app and you control the links, you could append width and height query params or custom headers to each request before it goes out.
0 commit comments