state-in-url 4.0.1 → 4.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +53 -18
  2. package/package.json +8 -7
package/README.md CHANGED
@@ -3,7 +3,8 @@ English | [한국어](./README.KO.md) | [简体中文](./README.CN.md)
3
3
  <div align="center">
4
4
  <img src="/assets/Logo_big.png?raw=true" alt="state-in-url logo"/>
5
5
 
6
- <div><h2>Easily share complex state objects between unrelated React components, preserve types and structure, with TS validation. Without any hasssle or boilerplate.</h2></div>
6
+ <div><h2> Store any complex state in query parameters, URL synchronization (aka deep links) made easy. Share state between any unrelated components. With support of static types validation and server side rendering.</h2></div>
7
+
7
8
 
8
9
  </div>
9
10
 
@@ -50,26 +51,38 @@ Share if it useful for you.
50
51
 
51
52
  </div>
52
53
 
53
- # Why use state-in-url?
54
+ # Why use `state-in-url`?
55
+
56
+ Store any user state in query parameters; imagine JSON in a browser URL, while keeping types and structure of data.
57
+ Dead simple, fast, and with static Typescript validation. Deep links, aka URL synchronization, made easy.
58
+
59
+ Contains `useUrlState` hook for Next.js and react-router, and helpers for anything else on JS.
60
+ Since modern browsers support huge URLs and users don't care about query strings (it is a select all and copy/past workflow).
61
+
62
+ Time to use query string for state management, as it was originally intended.
63
+ This library does all mundane stuff for you.
54
64
 
55
- `state-in-url` Simple state management with optional URL sync. Good for implementing deep links. Share complex states between unrelated React components, TS-friendly, NextJS compatible. Most of users don't care about URL, so, can use it to store your app state.
65
+ This library is a good alternative for NUQS.
56
66
 
57
67
  # Use cases
58
68
 
59
- - 🧮 Store unsaved user forms in URL
60
- - 🙃 Share the state between different components without changing url, good as alternative to signals and other state management tools
61
- - 🧠 Sync data between unrelated client components
69
+ - 💾 Store unsaved user forms or page filters in URL
70
+ - 🧠 Just sync data between unrelated client components without touching URI
62
71
  - 🔗 Shareable URLs with application state (Deep linking, URL state synchronization)
63
72
  - 🔄 Easy state persistence across page reloads
64
73
 
65
74
  # Features
66
75
 
67
- - 🧩 **Simple**: No providers, reducers, boilerplate or new concepts, API similar to React.useState
68
- - 📘 **Typescript support and type Safety**: Preserves data types and structure, good developer experience with IDE suggestions, strong typing and JSDoc comments
69
- - ⚛️ **Framework Flexibility**: Separate hooks for Next.js and React.js applications, and functions for pure JS
70
- - ⚙ **Well tested**: Unit tests and Playwright tests, high quality and support
71
- - ⚡ **Fast**: Minimal rerenders, less than [1ms](https://github.com/asmyshlyaev177/state-in-url/blob/87c8c7c995c5cd7d9e7aa039c30bfe64b24abe4b/packages/urlstate/encoder/encoder.test.ts#L185) to encode and decode an object
72
- - 🪶 **Lightweight**: Zero dependencies for a smaller footprint
76
+ - 🧩 **Simple**: No providers, reducers, boilerplate or new concepts, API similar to `React.useState`
77
+ - 📘 **Typescript validation**: State is just an object, automatic static validation in IDE/tests according to Typescript definition
78
+ - ✨ **Complex data**: Nested objects, dates and arrays, works same as JSON, but in URL
79
+ - 🔵 **Server Side Rendering**: Can use it in Server Components, Next.js 14 and 15 are supported
80
+ - ⚙ **Well tested**: Unit tests and Playwright tests for Chrome/Firefox/Safari
81
+ - ⚡ **Fast**: Minimal rerenders, less than [1ms](https://github.com/asmyshlyaev177/state-in-url/blob/87c8c7c995c5cd7d9e7aa039c30bfe64b24abe4b/packages/urlstate/encoder/encoder.test.ts#L185) to encode and decode big object
82
+ - 🪶 **Lightweight**: Zero dependencies, library less than 2KB
83
+ - 👍 **DX**: Good developer experience, documentation, JSDoc comments, and examples
84
+ - ⚛️ **Framework Flexibility**: Hooks for `Next.js` and `react-router`, helpers to use it with other frameworks or pure JS
85
+ - 📃 **Permissive license**: MIT
73
86
 
74
87
  ## Table of content
75
88
 
@@ -113,7 +126,8 @@ Possibly need to set `"module": "ES2022"`, or `"module": "ESNext"`
113
126
 
114
127
  ## useUrlState
115
128
 
116
- `useUrlState` is a custom React hook for Next.js/React-Router applications that make communication between client components easy. It allows you to share any complex state and sync it with the URL search parameters, providing a way to persist state across page reloads and share application state via URLs.
129
+ Main hook that takes initial state as parameter and returns state object, callback to update url, and callback to update only state.
130
+ All components that use the same `state` object are automatically synchronized.
117
131
 
118
132
  ## useUrlState hook for Next.js
119
133
 
@@ -125,11 +139,11 @@ Possibly need to set `"module": "ES2022"`, or `"module": "ESNext"`
125
139
 
126
140
  #### Basic
127
141
 
128
- 1. Define state shape
142
+ 1. Define state shape with default values
129
143
 
130
144
  ```typescript
131
145
  // userState.ts
132
- // State shape should be stored in a constant, don't pass an object directly
146
+ // Only parameters with value different from default will go to the url.
133
147
  export const userState: UserState = { name: '', age: 0 }
134
148
 
135
149
  type UserState = { name: string, age: number }
@@ -154,13 +168,13 @@ function MyComponent() {
154
168
  return (
155
169
  <div>
156
170
  <input value={urlState.name}
157
- onChange={(ev) => { setUrl({ name: ev.target.value }) }}
171
+ // same api as React.useState, e.g. setUrl(currVal => currVal + 1)
172
+ onChange={(ev) => setUrl({ name: ev.target.value }) }
158
173
  />
159
174
  <input value={urlState.age}
160
- onChange={(ev) => { setUrl({ age: +ev.target.value }) }}
175
+ onChange={(ev) => setUrl({ age: +ev.target.value }) }
161
176
  />
162
177
 
163
- // same api as React.useState
164
178
  <input value={urlState.name}
165
179
  onChange={(ev) => { setState(curr => ({ ...curr, name: ev.target.value })) }}
166
180
  // Can update state immediately but sync change to url as needed
@@ -510,6 +524,27 @@ function SettingsComponent() {
510
524
  - Avoid storing sensitive information in URL parameters (SSN, API keys etc)
511
525
  - Use this [extension](https://marketplace.visualstudio.com/items?itemName=yoavbls.pretty-ts-errors) for readable TS errors
512
526
 
527
+ Can create state hooks for slices of state, and reuse them across application. For example:
528
+ ```Typescript
529
+ type UserState = {
530
+ name: string;
531
+ age: number;
532
+ other: { id: string, value: number }[]
533
+ };
534
+ const userState = {
535
+ name: '',
536
+ age: 0,
537
+ other: [],
538
+ };
539
+
540
+ export const useUserState = () => {
541
+ const { urlState, setUrl } = useUrlState({ defaultState: userState });
542
+
543
+ return { userState: urlState, setUserState: setUrl };;
544
+ }
545
+
546
+ ```
547
+
513
548
  ## Gothas
514
549
 
515
550
  1. Can pass only serializable values, `Function`, `BigInt` or `Symbol` won't work, probably things like `ArrayBuffer` neither. Everything that can be serialized to JSON will work.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "state-in-url",
3
- "version": "4.0.1",
3
+ "version": "4.0.2",
4
4
  "description": "Easily share complex state objects between unrelated React components, preserve types and structure, with TS validation. Deep links and url state synchronization wthout any hasssle or boilerplate.",
5
5
  "homepage": "https://state-in-url.dev",
6
6
  "keywords": [
@@ -13,7 +13,6 @@
13
13
  "useUrlState",
14
14
  "state in url",
15
15
  "client components communication",
16
- "signals alternative",
17
16
  "query string",
18
17
  "search params",
19
18
  "query params",
@@ -25,7 +24,8 @@
25
24
  "reactjs",
26
25
  "react",
27
26
  "NextJS",
28
- "Next.js"
27
+ "Next.js",
28
+ "nuqs alternative"
29
29
  ],
30
30
  "repository": {
31
31
  "type": "git",
@@ -122,8 +122,9 @@
122
122
  "kill-next": "wireit",
123
123
  "kill-vite": "wireit",
124
124
  "kill": "wireit",
125
- "cleanup": "rm -rf dist",
126
- "reinstall": "rm -rf dist .wireit node_modules packages/example-nextjs14/node_modules packages/example-nextjs14/.next packages/example-react/node_modules && npm install",
125
+ "rmdist": "rm -rf dist",
126
+ "cleanup": "rm -rf dist .wireit node_modules test-results playwright-report coverage-reports nyc_coverage packages/example-nextjs14/node_modules packages/example-nextjs14/.next packages/example-nextjs15/node_modules packages/example-nextjs15/.next packages/example-react/node_modules packages/example-react-router6/node_modules",
127
+ "reinstall": "npm run cleanup && npm install",
127
128
  "setup": "playwright install --with-deps",
128
129
  "prepack": "npm run build && cp package.json dist/package.json && npm run build:demo",
129
130
  "prepare": "npx husky"
@@ -191,7 +192,7 @@
191
192
  }
192
193
  },
193
194
  "dependencies": [
194
- "cleanup"
195
+ "rmdist"
195
196
  ]
196
197
  },
197
198
  "dev:router6": {
@@ -305,7 +306,7 @@
305
306
  "build": {
306
307
  "command": "rollup -c rollup.config.js --bundleConfigAsCjs",
307
308
  "dependencies": [
308
- "cleanup"
309
+ "rmdist"
309
310
  ]
310
311
  }
311
312
  },