Skip to content

Commit dafe6c7

Browse files
committed
Fix: Update readme
1 parent 4fc531e commit dafe6c7

2 files changed

Lines changed: 77 additions & 52 deletions

File tree

README.md

Lines changed: 77 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,48 @@
11
# 💬 Responsive System
22

3-
## Motivation
3+
A tiny (yet powerful) system for when CSS media queries aren't enough.
4+
5+
![gzip size](https://badgen.net/bundlephobia/minzip/react-responsive-system) ![weekly npm downloads](https://badgen.net/npm/dw/react-responsive-system) ![typescript types included](https://badgen.net/npm/types/react-responsive-system)
46

5-
Check out this [post](https://ayhota.com/blog/articles/responsive-react-components) to learn more about the motivation behind Responsive System.
7+
## Motivation
68

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.
810

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!
1012

1113
## What does it look like?
1214

15+
You give us a list of screen size boundaries where things might need to change ("breakpoints").
16+
17+
```js
18+
const breakpoints = {
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+
1330
```jsx
1431
const MyResponsiveComponent() {
15-
const message = useResponsiveValue<string>("Your screen is big", { onSmallScreens: "Your screen is small" });
16-
const number = useResponsiveValue<number>(100, { onMediumScreens: 50, onSmallScreensOrSmaller: 25 });
17-
// don't get hung up on the "onXScreens" language; that's fully customizable!
32+
const message = useResponsiveValue(
33+
"Your screen is big", // default value
34+
{ small: "Your screen is small" } // overrides
35+
);
36+
// works with any type of value
37+
const number = useResponsiveValue(
38+
100,
39+
{ large: 50, medium: 25 }
40+
);
1841
...
1942
}
2043
```
2144

22-
## Getting Started
45+
## Setup
2346

2447
```bash
2548
# npm
@@ -29,16 +52,16 @@ npm install react-responsive-system
2952
yarn add react-responsive-system
3053
```
3154

32-
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)
3558
4. [Make your components responsive](#4-make-your-components-responsive)
3659

37-
### 1. Define your breakpoints in JS
60+
### 1. Define your breakpoints
3861

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.
4063
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:
4265

4366
```js
4467
/* responsiveSystem.js/ts */
@@ -51,11 +74,9 @@ const breakpoints = {
5174
};
5275
```
5376

54-
The values that you provide are the "maximum pixel-widths" for that screen class. 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`.
5578

56-
### 2. Generate your custom Responsive System with `createResponsiveSystem`
57-
58-
Here, you'll configure Responsive System with your breakpoints.
79+
### 2. Initialize the system
5980

6081
```js
6182
/* responsiveSystem.js/ts */
@@ -66,18 +87,20 @@ const breakpoints = {
6687
// your breakpoints here
6788
};
6889

69-
export const { ScreenClassProvider, useResponsiveValue } = createResponsiveSystem({
90+
const { ScreenClassProvider, useResponsiveValue } = createResponsiveSystem({
7091
breakpoints,
7192
});
93+
94+
export { ScreenClassProvider, useResponsiveValue };
7295
```
7396

74-
Let's break this down a little bit.
97+
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).
7598

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
77100

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.
79102

80-
```js
103+
```jsx
81104
/* index.jsx/tsx */
82105

83106
import { ScreenClassProvider } from './responsiveSystem';
@@ -94,23 +117,24 @@ ReactDOM.render(
94117

95118
Now that the app is aware of the current screen class, we can declare values that dynamically change to fit any screen!
96119

97-
```js
98-
const MyResponsiveComponent() {
99-
const message = useResponsiveValue<string>("Your screen is big", { sm: "Your screen is small" });
100-
const number = useResponsiveValue<number>(100, { md: 50, sm: 25, xs: 5 });
101-
// ...
120+
```jsx
121+
function ImageGallery() {
122+
const imagesToShow = useResponsiveValue(
123+
4 // show 4 images by default
124+
{
125+
md: 2, // on medium screens, show 2
126+
sm: 1, // on small screens, only show 1
127+
}
128+
);
129+
return <Gallery imagesToShow={imagesToShow} />
102130
}
103131
```
104132

105133
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.
106134

107-
## Examples
108-
109-
[TypeScript + Parcel](https://github.com/ejhammond/react-responsive-system/tree/master/examples/typescript)
110-
111135
## Cascading
112136

113-
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`.
114138

115139
This is where `cascadeMode` comes in.
116140

@@ -121,10 +145,10 @@ This is where `cascadeMode` comes in.
121145
This is the default configuration. There is no implicit overriding in this mode.
122146

123147
```js
124-
const number = useResponsiveValue('default', { md: 'overridden' });
148+
const number = useResponsiveValue('default', { md: 'medium' });
125149
```
126150

127-
Result:
151+
Results on different screen sizes:
128152

129153
- xl: "default"
130154
- lg: "default"
@@ -140,7 +164,7 @@ In Desktop First mode, your overrides implicitly override everything smaller. Co
140164
const number = useResponsiveValue('default', { md: 'overridden' });
141165
```
142166

143-
Result:
167+
Results on different screen sizes:
144168

145169
- xl: "default"
146170
- lg: "default"
@@ -156,7 +180,7 @@ In Mobile First mode, your overrides implicitly override everything larger. Conc
156180
const number = useResponsiveValue('default', { md: 'overridden' });
157181
```
158182

159-
Result:
183+
Results on different screen sizes:
160184

161185
- xl: "overridden"
162186
- lg: "overridden"
@@ -175,9 +199,13 @@ export const { ScreenClassProvider, useResponsiveValue } = createResponsiveSyste
175199
});
176200
```
177201

202+
## Examples
203+
204+
[TypeScript + Parcel](https://github.com/ejhammond/react-responsive-system/tree/master/examples/typescript)
205+
178206
## Server-Side Rendering
179207

180-
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.
181209

182210
```js
183211
export const { ScreenClassProvider, useResponsiveValue } = createResponsiveSystem({
@@ -194,32 +222,30 @@ This is the easiest approach. If you don't SSR, then you don't have to worry abo
194222

195223
### Client-Only Components
196224

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.
198226

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.
200228

201229
```jsx
202230
function ClientOnly({ placeholder, children }) {
203-
const isOnClient = useRef(false);
231+
const [isOnClient, setIsOnClient] = useState(false);
204232
useEffect(() => {
205-
// useEffect only runs on the client
206-
isOnClient.current = true;
233+
setIsOnClient(true);
207234
}, []);
208-
// will return `placeholder` on the server and `children` on the client
209-
return isOnClient.current ? children : placeholder;
235+
return isOnClient ? children : placeholder;
210236
}
211-
// usage
212-
<ClientOnly placeholder={<PlaceholderContent />}>
213-
<ResponsiveComponent />
214-
</ClientOnly>;
215237
```
216238

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+
217241
### Smart Server
218242

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+
219245
This route is tricky, but if you want to try it, here are some ideas:
220246

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.
223249

224250
## Extras
225251

examples/typescript/responsiveSystem.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ const breakpoints = {
88
};
99

1010
export const { ScreenClassProvider, useResponsiveValue } = createResponsiveSystem({
11-
defaultScreenClass: 'lg',
1211
breakpoints,
1312
cascadeMode: 'mobile-first',
1413
});

0 commit comments

Comments
 (0)