state-in-url 2.1.0 → 2.2.0
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.
- package/README.CN.md +2 -1
- package/README.KO.md +2 -1
- package/README.md +21 -21
- package/dist/next/useUrlState/useUrlState.d.ts +36 -29
- package/dist/next/useUrlState/useUrlState.mjs +1 -1
- package/dist/useSharedState/useSharedState.mjs +1 -1
- package/dist/useUrlStateBase/useUrlStateBase.mjs +1 -1
- package/package.json +4 -4
package/README.CN.md
CHANGED
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|

|
|
26
26
|
|
|
27
27
|
<a href="https://state-in-url-asmyshlyaev177.vercel.app/" target="_blank">演示</a> |
|
|
28
|
+
<a href="https://state-in-url.netlify.app/" target="_blank">DEMO2</a> |
|
|
28
29
|
<a href ="https://codesandbox.io/p/github/asmyshlyaev177/state-in-url/main?layout=%257B%2522sidebarPanel%2522%253A%2522EXPLORER%2522%252C%2522rootPanelGroup%2522%253A%257B%2522direction%2522%253A%2522horizontal%2522%252C%2522contentType%2522%253A%2522UNKNOWN%2522%252C%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522id%2522%253A%2522ROOT_LAYOUT%2522%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522contentType%2522%253A%2522UNKNOWN%2522%252C%2522direction%2522%253A%2522vertical%2522%252C%2522id%2522%253A%2522clyk5bd9y00062v6jspcfrkx7%2522%252C%2522sizes%2522%253A%255B100%252C0%255D%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522contentType%2522%253A%2522EDITOR%2522%252C%2522direction%2522%253A%2522horizontal%2522%252C%2522id%2522%253A%2522EDITOR%2522%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL%2522%252C%2522contentType%2522%253A%2522EDITOR%2522%252C%2522id%2522%253A%2522clyk5bd9x00022v6jyg71cr9e%2522%257D%255D%257D%252C%257B%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522contentType%2522%253A%2522SHELLS%2522%252C%2522direction%2522%253A%2522horizontal%2522%252C%2522id%2522%253A%2522SHELLS%2522%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL%2522%252C%2522contentType%2522%253A%2522SHELLS%2522%252C%2522id%2522%253A%2522clyk5bd9x00042v6jsos2y043%2522%257D%255D%257D%255D%257D%252C%257B%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522contentType%2522%253A%2522DEVTOOLS%2522%252C%2522direction%2522%253A%2522vertical%2522%252C%2522id%2522%253A%2522DEVTOOLS%2522%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL%2522%252C%2522contentType%2522%253A%2522DEVTOOLS%2522%252C%2522id%2522%253A%2522clyk5bd9x00052v6j5r632b12%2522%257D%255D%257D%255D%252C%2522sizes%2522%253A%255B50%252C50%255D%257D%252C%2522tabbedPanels%2522%253A%257B%2522clyk5bd9x00022v6jyg71cr9e%2522%253A%257B%2522tabs%2522%253A%255B%257B%2522id%2522%253A%2522clyk5bd9w00012v6j83rq3bvo%2522%252C%2522mode%2522%253A%2522permanent%2522%252C%2522type%2522%253A%2522FILE%2522%252C%2522filepath%2522%253A%2522%252FREADME.md%2522%252C%2522state%2522%253A%2522IDLE%2522%257D%255D%252C%2522id%2522%253A%2522clyk5bd9x00022v6jyg71cr9e%2522%252C%2522activeTabId%2522%253A%2522clyk5bd9w00012v6j83rq3bvo%2522%257D%252C%2522clyk5bd9x00052v6j5r632b12%2522%253A%257B%2522id%2522%253A%2522clyk5bd9x00052v6j5r632b12%2522%252C%2522activeTabId%2522%253A%2522clyk5bdjx000b2v6jfc8ae464%2522%252C%2522tabs%2522%253A%255B%257B%2522type%2522%253A%2522SETUP_TASKS%2522%252C%2522id%2522%253A%2522clyk5bdjx000b2v6jfc8ae464%2522%252C%2522mode%2522%253A%2522permanent%2522%257D%252C%257B%2522type%2522%253A%2522UNASSIGNED_PORT%2522%252C%2522port%2522%253A2222%252C%2522id%2522%253A%2522clyk5cjbo004d2v6j3u55k74g%2522%252C%2522mode%2522%253A%2522permanent%2522%257D%252C%257B%2522type%2522%253A%2522ENV_SETUP%2522%252C%2522id%2522%253A%2522clyk5h8dp000r2v6j0r7kc7qq%2522%252C%2522mode%2522%253A%2522permanent%2522%257D%255D%257D%252C%2522clyk5bd9x00042v6jsos2y043%2522%253A%257B%2522id%2522%253A%2522clyk5bd9x00042v6jsos2y043%2522%252C%2522activeTabId%2522%253A%2522clyk5cbuv001q2v6joegrxxv6%2522%252C%2522tabs%2522%253A%255B%257B%2522id%2522%253A%2522clyk5bd9x00032v6jtfhj316o%2522%252C%2522mode%2522%253A%2522permanent%2522%252C%2522type%2522%253A%2522NEW_TERMINAL%2522%257D%252C%257B%2522type%2522%253A%2522TASK_LOG%2522%252C%2522taskId%2522%253A%2522dev%2522%252C%2522id%2522%253A%2522clyk5cbuv001q2v6joegrxxv6%2522%252C%2522mode%2522%253A%2522permanent%2522%257D%252C%257B%2522type%2522%253A%2522TASK_LOG%2522%252C%2522taskId%2522%253A%2522cleanupDist%2522%252C%2522id%2522%253A%2522clyk5dgvo005i2v6jj950sxft%2522%252C%2522mode%2522%253A%2522permanent%2522%257D%255D%257D%257D%252C%2522showDevtools%2522%253Atrue%252C%2522showShells%2522%253Atrue%252C%2522showSidebar%2522%253Atrue%252C%2522sidebarPanelSize%2522%253A15%257D" target="_blank">Demo on Codesandbox</a>
|
|
29
30
|
|
|
30
31
|
<hr />
|
|
@@ -91,7 +92,7 @@ pnpm add state-in-url
|
|
|
91
92
|
|
|
92
93
|
## Next.js的useUrlState钩子
|
|
93
94
|
|
|
94
|
-
[文档](
|
|
95
|
+
[文档](packages/urlstate/next/useUrlState#api)
|
|
95
96
|
|
|
96
97
|
`useUrlState`是一个为Next.js应用程序设计的自定义React钩子,使客户端组件之间的通信变得简单。它允许你共享任何复杂的状态并将其与URL搜索参数同步,提供了一种在页面重新加载之间持久化状态并通过URL共享应用程序状态的方法。
|
|
97
98
|
|
package/README.KO.md
CHANGED
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
|
|
30
30
|
|
|
31
31
|
<a href="https://state-in-url-asmyshlyaev177.vercel.app/" target="_blank">데모</a> |
|
|
32
|
+
<a href="https://state-in-url.netlify.app/" target="_blank">DEMO2</a> |
|
|
32
33
|
<a href ="https://codesandbox.io/p/github/asmyshlyaev177/state-in-url/main?layout=%257B%2522sidebarPanel%2522%253A%2522EXPLORER%2522%252C%2522rootPanelGroup%2522%253A%257B%2522direction%2522%253A%2522horizontal%2522%252C%2522contentType%2522%253A%2522UNKNOWN%2522%252C%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522id%2522%253A%2522ROOT_LAYOUT%2522%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522contentType%2522%253A%2522UNKNOWN%2522%252C%2522direction%2522%253A%2522vertical%2522%252C%2522id%2522%253A%2522clyk5bd9y00062v6jspcfrkx7%2522%252C%2522sizes%2522%253A%255B100%252C0%255D%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522contentType%2522%253A%2522EDITOR%2522%252C%2522direction%2522%253A%2522horizontal%2522%252C%2522id%2522%253A%2522EDITOR%2522%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL%2522%252C%2522contentType%2522%253A%2522EDITOR%2522%252C%2522id%2522%253A%2522clyk5bd9x00022v6jyg71cr9e%2522%257D%255D%257D%252C%257B%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522contentType%2522%253A%2522SHELLS%2522%252C%2522direction%2522%253A%2522horizontal%2522%252C%2522id%2522%253A%2522SHELLS%2522%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL%2522%252C%2522contentType%2522%253A%2522SHELLS%2522%252C%2522id%2522%253A%2522clyk5bd9x00042v6jsos2y043%2522%257D%255D%257D%255D%257D%252C%257B%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522contentType%2522%253A%2522DEVTOOLS%2522%252C%2522direction%2522%253A%2522vertical%2522%252C%2522id%2522%253A%2522DEVTOOLS%2522%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL%2522%252C%2522contentType%2522%253A%2522DEVTOOLS%2522%252C%2522id%2522%253A%2522clyk5bd9x00052v6j5r632b12%2522%257D%255D%257D%255D%252C%2522sizes%2522%253A%255B50%252C50%255D%257D%252C%2522tabbedPanels%2522%253A%257B%2522clyk5bd9x00022v6jyg71cr9e%2522%253A%257B%2522tabs%2522%253A%255B%257B%2522id%2522%253A%2522clyk5bd9w00012v6j83rq3bvo%2522%252C%2522mode%2522%253A%2522permanent%2522%252C%2522type%2522%253A%2522FILE%2522%252C%2522filepath%2522%253A%2522%252FREADME.md%2522%252C%2522state%2522%253A%2522IDLE%2522%257D%255D%252C%2522id%2522%253A%2522clyk5bd9x00022v6jyg71cr9e%2522%252C%2522activeTabId%2522%253A%2522clyk5bd9w00012v6j83rq3bvo%2522%257D%252C%2522clyk5bd9x00052v6j5r632b12%2522%253A%257B%2522id%2522%253A%2522clyk5bd9x00052v6j5r632b12%2522%252C%2522activeTabId%2522%253A%2522clyk5bdjx000b2v6jfc8ae464%2522%252C%2522tabs%2522%253A%255B%257B%2522type%2522%253A%2522SETUP_TASKS%2522%252C%2522id%2522%253A%2522clyk5bdjx000b2v6jfc8ae464%2522%252C%2522mode%2522%253A%2522permanent%2522%257D%252C%257B%2522type%2522%253A%2522UNASSIGNED_PORT%2522%252C%2522port%2522%253A2222%252C%2522id%2522%253A%2522clyk5cjbo004d2v6j3u55k74g%2522%252C%2522mode%2522%253A%2522permanent%2522%257D%252C%257B%2522type%2522%253A%2522ENV_SETUP%2522%252C%2522id%2522%253A%2522clyk5h8dp000r2v6j0r7kc7qq%2522%252C%2522mode%2522%253A%2522permanent%2522%257D%255D%257D%252C%2522clyk5bd9x00042v6jsos2y043%2522%253A%257B%2522id%2522%253A%2522clyk5bd9x00042v6jsos2y043%2522%252C%2522activeTabId%2522%253A%2522clyk5cbuv001q2v6joegrxxv6%2522%252C%2522tabs%2522%253A%255B%257B%2522id%2522%253A%2522clyk5bd9x00032v6jtfhj316o%2522%252C%2522mode%2522%253A%2522permanent%2522%252C%2522type%2522%253A%2522NEW_TERMINAL%2522%257D%252C%257B%2522type%2522%253A%2522TASK_LOG%2522%252C%2522taskId%2522%253A%2522dev%2522%252C%2522id%2522%253A%2522clyk5cbuv001q2v6joegrxxv6%2522%252C%2522mode%2522%253A%2522permanent%2522%257D%252C%257B%2522type%2522%253A%2522TASK_LOG%2522%252C%2522taskId%2522%253A%2522cleanupDist%2522%252C%2522id%2522%253A%2522clyk5dgvo005i2v6jj950sxft%2522%252C%2522mode%2522%253A%2522permanent%2522%257D%255D%257D%257D%252C%2522showDevtools%2522%253Atrue%252C%2522showShells%2522%253Atrue%252C%2522showSidebar%2522%253Atrue%252C%2522sidebarPanelSize%2522%253A15%257D" target="_blank">Demo on Codesandbox</a>
|
|
33
34
|
|
|
34
35
|
|
|
@@ -98,7 +99,7 @@ pnpm add state-in-url
|
|
|
98
99
|
|
|
99
100
|
## Next.js용 useUrlState 훅
|
|
100
101
|
|
|
101
|
-
[문서](
|
|
102
|
+
[문서](packages/urlstate/next/useUrlState#api)
|
|
102
103
|
|
|
103
104
|
`useUrlState`는 Next.js 애플리케이션을 위한 사용자 정의 React 훅으로, 클라이언트 컴포넌트 간의 통신을 쉽게 만듭니다. 복잡한 상태를 공유하고 URL 검색 매개변수와 동기화할 수 있게 해주어, 페이지 새로고침 시 상태를 유지하고 URL을 통해 애플리케이션 상태를 공유할 수 있습니다.
|
|
104
105
|
|
package/README.md
CHANGED
|
@@ -2,18 +2,15 @@ English | [한국어](./README.KO.md) | [简体中文](./README.CN.md)
|
|
|
2
2
|
|
|
3
3
|
<h1 align="center">state-in-url</h1>
|
|
4
4
|
|
|
5
|
-
|
|
6
5
|
<div align="center">
|
|
7
6
|
<img src="/assets/logo.svg?raw=true" alt="Library logo"/>
|
|
8
7
|
|
|
9
8
|
<div>Easily share state between unrelated React components, with IDE autocomplete and TS validation. Without any hasssle or boilerplate. </div>
|
|
10
9
|
</div>
|
|
11
10
|
|
|
12
|
-
|
|
13
11
|
<div align="center">
|
|
14
12
|
<hr />
|
|
15
13
|
|
|
16
|
-
|
|
17
14
|
[](https://www.npmjs.com/package/state-in-url)
|
|
18
15
|

|
|
19
16
|
[](https://app.codacy.com/gh/asmyshlyaev177/state-in-url/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade)
|
|
@@ -27,11 +24,10 @@ English | [한국어](./README.KO.md) | [简体中文](./README.CN.md)
|
|
|
27
24
|
|
|
28
25
|

|
|
29
26
|
|
|
30
|
-
|
|
31
27
|
<a href="https://state-in-url-asmyshlyaev177.vercel.app/" target="_blank">DEMO</a> |
|
|
28
|
+
<a href="https://state-in-url.netlify.app/" target="_blank">DEMO2</a> |
|
|
32
29
|
<a href ="https://codesandbox.io/p/github/asmyshlyaev177/state-in-url/main?layout=%257B%2522sidebarPanel%2522%253A%2522EXPLORER%2522%252C%2522rootPanelGroup%2522%253A%257B%2522direction%2522%253A%2522horizontal%2522%252C%2522contentType%2522%253A%2522UNKNOWN%2522%252C%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522id%2522%253A%2522ROOT_LAYOUT%2522%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522contentType%2522%253A%2522UNKNOWN%2522%252C%2522direction%2522%253A%2522vertical%2522%252C%2522id%2522%253A%2522clyk5bd9y00062v6jspcfrkx7%2522%252C%2522sizes%2522%253A%255B100%252C0%255D%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522contentType%2522%253A%2522EDITOR%2522%252C%2522direction%2522%253A%2522horizontal%2522%252C%2522id%2522%253A%2522EDITOR%2522%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL%2522%252C%2522contentType%2522%253A%2522EDITOR%2522%252C%2522id%2522%253A%2522clyk5bd9x00022v6jyg71cr9e%2522%257D%255D%257D%252C%257B%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522contentType%2522%253A%2522SHELLS%2522%252C%2522direction%2522%253A%2522horizontal%2522%252C%2522id%2522%253A%2522SHELLS%2522%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL%2522%252C%2522contentType%2522%253A%2522SHELLS%2522%252C%2522id%2522%253A%2522clyk5bd9x00042v6jsos2y043%2522%257D%255D%257D%255D%257D%252C%257B%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522contentType%2522%253A%2522DEVTOOLS%2522%252C%2522direction%2522%253A%2522vertical%2522%252C%2522id%2522%253A%2522DEVTOOLS%2522%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL%2522%252C%2522contentType%2522%253A%2522DEVTOOLS%2522%252C%2522id%2522%253A%2522clyk5bd9x00052v6j5r632b12%2522%257D%255D%257D%255D%252C%2522sizes%2522%253A%255B50%252C50%255D%257D%252C%2522tabbedPanels%2522%253A%257B%2522clyk5bd9x00022v6jyg71cr9e%2522%253A%257B%2522tabs%2522%253A%255B%257B%2522id%2522%253A%2522clyk5bd9w00012v6j83rq3bvo%2522%252C%2522mode%2522%253A%2522permanent%2522%252C%2522type%2522%253A%2522FILE%2522%252C%2522filepath%2522%253A%2522%252FREADME.md%2522%252C%2522state%2522%253A%2522IDLE%2522%257D%255D%252C%2522id%2522%253A%2522clyk5bd9x00022v6jyg71cr9e%2522%252C%2522activeTabId%2522%253A%2522clyk5bd9w00012v6j83rq3bvo%2522%257D%252C%2522clyk5bd9x00052v6j5r632b12%2522%253A%257B%2522id%2522%253A%2522clyk5bd9x00052v6j5r632b12%2522%252C%2522activeTabId%2522%253A%2522clyk5bdjx000b2v6jfc8ae464%2522%252C%2522tabs%2522%253A%255B%257B%2522type%2522%253A%2522SETUP_TASKS%2522%252C%2522id%2522%253A%2522clyk5bdjx000b2v6jfc8ae464%2522%252C%2522mode%2522%253A%2522permanent%2522%257D%252C%257B%2522type%2522%253A%2522UNASSIGNED_PORT%2522%252C%2522port%2522%253A2222%252C%2522id%2522%253A%2522clyk5cjbo004d2v6j3u55k74g%2522%252C%2522mode%2522%253A%2522permanent%2522%257D%252C%257B%2522type%2522%253A%2522ENV_SETUP%2522%252C%2522id%2522%253A%2522clyk5h8dp000r2v6j0r7kc7qq%2522%252C%2522mode%2522%253A%2522permanent%2522%257D%255D%257D%252C%2522clyk5bd9x00042v6jsos2y043%2522%253A%257B%2522id%2522%253A%2522clyk5bd9x00042v6jsos2y043%2522%252C%2522activeTabId%2522%253A%2522clyk5cbuv001q2v6joegrxxv6%2522%252C%2522tabs%2522%253A%255B%257B%2522id%2522%253A%2522clyk5bd9x00032v6jtfhj316o%2522%252C%2522mode%2522%253A%2522permanent%2522%252C%2522type%2522%253A%2522NEW_TERMINAL%2522%257D%252C%257B%2522type%2522%253A%2522TASK_LOG%2522%252C%2522taskId%2522%253A%2522dev%2522%252C%2522id%2522%253A%2522clyk5cbuv001q2v6joegrxxv6%2522%252C%2522mode%2522%253A%2522permanent%2522%257D%252C%257B%2522type%2522%253A%2522TASK_LOG%2522%252C%2522taskId%2522%253A%2522cleanupDist%2522%252C%2522id%2522%253A%2522clyk5dgvo005i2v6jj950sxft%2522%252C%2522mode%2522%253A%2522permanent%2522%257D%255D%257D%257D%252C%2522showDevtools%2522%253Atrue%252C%2522showShells%2522%253Atrue%252C%2522showSidebar%2522%253Atrue%252C%2522sidebarPanelSize%2522%253A15%257D" target="_blank">Demo on Codesandbox</a>
|
|
33
30
|
|
|
34
|
-
|
|
35
31
|
<hr />
|
|
36
32
|
|
|
37
33
|
Add a ⭐️ to support the project!
|
|
@@ -40,11 +36,10 @@ Add a ⭐️ to support the project!
|
|
|
40
36
|
|
|
41
37
|
</div>
|
|
42
38
|
|
|
43
|
-
|
|
39
|
+
## Why use state-in-url?
|
|
44
40
|
|
|
45
41
|
`state-in-url` Simple state management with optional URL sync. Share complex states between unrelated React components, TS-friendly, NextJS compatible.
|
|
46
42
|
|
|
47
|
-
|
|
48
43
|
# Use cases
|
|
49
44
|
|
|
50
45
|
- 🧮 Store unsaved user forms in URL
|
|
@@ -53,8 +48,6 @@ Add a ⭐️ to support the project!
|
|
|
53
48
|
- 🔗 Shareable URLs with full application state
|
|
54
49
|
- 🔄 Easy state persistence across page reloads
|
|
55
50
|
|
|
56
|
-
|
|
57
|
-
|
|
58
51
|
# Features
|
|
59
52
|
|
|
60
53
|
- 🧩 **Simple**: No providers, reducers, boilerplate or new concepts
|
|
@@ -64,7 +57,6 @@ Add a ⭐️ to support the project!
|
|
|
64
57
|
- ⚡ **Fast**: Minimal rerenders
|
|
65
58
|
- 🪶 **Lightweight**: Zero dependencies for a smaller footprint
|
|
66
59
|
|
|
67
|
-
|
|
68
60
|
## Table of content
|
|
69
61
|
|
|
70
62
|
- [Installation](#installation)
|
|
@@ -100,7 +92,7 @@ In `tsconfig.json` in `compilerOptions` set `"moduleResolution": "Node16"` or `"
|
|
|
100
92
|
|
|
101
93
|
## useUrlState hook for Next.js
|
|
102
94
|
|
|
103
|
-
[Docs](
|
|
95
|
+
[Docs](packages/urlstate/next/useUrlState#api)
|
|
104
96
|
|
|
105
97
|
`useUrlState` is a custom React hook for Next.js 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.
|
|
106
98
|
|
|
@@ -129,8 +121,10 @@ import { countState } from './countState';
|
|
|
129
121
|
function MyComponent() {
|
|
130
122
|
// for use searchParams from server component
|
|
131
123
|
// e.g. export default async function Home({ searchParams }: { searchParams: object }) {
|
|
132
|
-
// const { state, updateState, updateUrl } = useUrlState(countState, searchParams);
|
|
133
|
-
|
|
124
|
+
// const { state, updateState, updateUrl } = useUrlState({ defaultState: countState, searchParams });
|
|
125
|
+
// can pass `replace` arg, it's control will `updateUrl` will use `rounter.push` or `router.replace`, default replace=true
|
|
126
|
+
// const { state, updateState, updateUrl } = useUrlState({ defaultState: countState, searchParams, replace: false });
|
|
127
|
+
const { state, updateState, updateUrl } = useUrlState({ defaultState: countState });
|
|
134
128
|
|
|
135
129
|
// won't let you to accidently mutate state directly, requires TS
|
|
136
130
|
// state.count = 2 // <- error
|
|
@@ -184,7 +178,7 @@ import { userSettings } from './userSettings';
|
|
|
184
178
|
|
|
185
179
|
function SettingsComponent() {
|
|
186
180
|
// `state` will infer from UserSettings type!
|
|
187
|
-
const { state, updateUrl } = useUrlState(userSettings);
|
|
181
|
+
const { state, updateUrl } = useUrlState({ defaultState: userSettings });
|
|
188
182
|
|
|
189
183
|
const toggleTheme = () => {
|
|
190
184
|
updateUrl(current => ({
|
|
@@ -221,7 +215,7 @@ function SettingsComponent() {
|
|
|
221
215
|
|
|
222
216
|
// Other component
|
|
223
217
|
function Component() {
|
|
224
|
-
const { state } = useUrlState(defaultSettings);
|
|
218
|
+
const { state } = useUrlState({ defaultState: defaultSettings });
|
|
225
219
|
|
|
226
220
|
return (
|
|
227
221
|
<div>
|
|
@@ -248,12 +242,18 @@ function Component() {
|
|
|
248
242
|
}, [state, updateUrl]);
|
|
249
243
|
```
|
|
250
244
|
|
|
245
|
+
Syncing state `onBlur` will be more aligned with real world usage.
|
|
246
|
+
|
|
247
|
+
```typescript
|
|
248
|
+
<input onBlur={() => updateUrl()} .../>
|
|
249
|
+
```
|
|
250
|
+
|
|
251
251
|
#### With server side rendering
|
|
252
252
|
|
|
253
253
|
```typescript
|
|
254
254
|
export default async function Home({ searchParams }: { searchParams: object }) {
|
|
255
255
|
return (
|
|
256
|
-
<Form
|
|
256
|
+
<Form searchParams={searchParams} />
|
|
257
257
|
)
|
|
258
258
|
}
|
|
259
259
|
|
|
@@ -263,8 +263,8 @@ import React from 'react';
|
|
|
263
263
|
import { useUrlState } from 'state-in-url/next';
|
|
264
264
|
import { form } from './form';
|
|
265
265
|
|
|
266
|
-
const Form = ({
|
|
267
|
-
const { state, updateState, updateUrl } = useUrlState(form,
|
|
266
|
+
const Form = ({ searchParams }: { searchParams: object }) => {
|
|
267
|
+
const { state, updateState, updateUrl } = useUrlState({ defaultState: form, searchParams });
|
|
268
268
|
}
|
|
269
269
|
```
|
|
270
270
|
|
|
@@ -329,6 +329,7 @@ function SettingsComponent() {
|
|
|
329
329
|
```
|
|
330
330
|
|
|
331
331
|
## `useSharedState` hook for React.js
|
|
332
|
+
|
|
332
333
|
Hook to share state between any React components, tested with Next.js and Vite.
|
|
333
334
|
|
|
334
335
|
```typescript
|
|
@@ -368,7 +369,7 @@ function SettingsComponent() {
|
|
|
368
369
|
## Gothas
|
|
369
370
|
|
|
370
371
|
1. Can pass only serializable values, `Function`, `BigInt` or `Symbol` won't work, probably things like `ArrayBuffer` neither.
|
|
371
|
-
2. Vercel servers limit size of headers (query string and other stuff) to **14KB**, so keep your URL state under ~5000 words. https://vercel.com/docs/errors/URL_TOO_LONG
|
|
372
|
+
2. Vercel servers limit size of headers (query string and other stuff) to **14KB**, so keep your URL state under ~5000 words. <https://vercel.com/docs/errors/URL_TOO_LONG>
|
|
372
373
|
3. Tested with `next.js` 14 with app router, no plans to support pages.
|
|
373
374
|
|
|
374
375
|
## Run locally
|
|
@@ -381,7 +382,6 @@ npm run dev
|
|
|
381
382
|
|
|
382
383
|
Go to [localhost:3000](http://localhost:3000)
|
|
383
384
|
|
|
384
|
-
|
|
385
385
|
## Contact & Support
|
|
386
386
|
|
|
387
387
|
- Create a [GitHub issue](https://github.com/asmyshlyaev177/state-in-url/issues) for bug reports, feature requests, or questions
|
|
@@ -394,7 +394,7 @@ This project is licensed under the [MIT license](https://github.com/asmyshlyaev1
|
|
|
394
394
|
|
|
395
395
|
## Inspiration
|
|
396
396
|
|
|
397
|
-
[Using URL to store state in Vue
|
|
397
|
+
[Using URL to store state in Vue](https://dev.to/jacobandrewsky/using-url-to-store-state-in-vue-275c)
|
|
398
398
|
|
|
399
399
|
[Storing state in the URL](https://antonz.org/storing-state/)
|
|
400
400
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { useRouter } from 'next/navigation';
|
|
2
1
|
import { type DeepReadonly, type JSONCompatible } from '../../utils';
|
|
3
2
|
/**
|
|
3
|
+
* @deprecated Pass arguments in a object `useUrlState({ defaultState: form, searchParams })`
|
|
4
|
+
*
|
|
4
5
|
* NextJS hook. Returns `state`, `updateState`, and `updateUrl` functions
|
|
5
6
|
*
|
|
6
7
|
* @param {JSONCompatible<T>} [defaultState] Fallback (default) values for state
|
|
@@ -23,34 +24,40 @@ import { type DeepReadonly, type JSONCompatible } from '../../utils';
|
|
|
23
24
|
* * Github {@link https://github.com/asmyshlyaev177/state-in-url/tree/main/packages/urlstate/next/useUrlState#api}
|
|
24
25
|
*/
|
|
25
26
|
export declare function useUrlState<T extends JSONCompatible>(defaultState: T, searchParams?: object): {
|
|
26
|
-
|
|
27
|
-
* * Example:
|
|
28
|
-
* ```ts
|
|
29
|
-
* updateState({ name: 'test' });
|
|
30
|
-
* // or
|
|
31
|
-
* updateState(curr => ({ ...curr, name: 'test' }) );
|
|
32
|
-
* ```
|
|
33
|
-
*
|
|
34
|
-
* * Github {@link https://github.com/asmyshlyaev177/state-in-url/tree/main/packages/urlstate/next/useUrlState#updatestate}
|
|
35
|
-
*/
|
|
27
|
+
state: DeepReadonly<T>;
|
|
36
28
|
updateState: (value: Partial<T> | Partial<DeepReadonly<T>> | ((currState: T) => T)) => void;
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
* ```ts
|
|
40
|
-
* updateUrl({ name: 'test' });
|
|
41
|
-
* // or
|
|
42
|
-
* updateUrl(curr => ({ ...curr, name: 'test' }), { replace: true, scroll: false } );
|
|
43
|
-
* ```
|
|
44
|
-
*
|
|
45
|
-
* * Github {@link https://github.com/asmyshlyaev177/state-in-url/tree/main/packages/urlstate/next/useUrlState#updateurl}
|
|
46
|
-
*/
|
|
47
|
-
updateUrl: (value?: Partial<T> | Partial<DeepReadonly<T>> | ((currState: T) => T) | undefined, options?: Options) => void;
|
|
48
|
-
state: DeepReadonly<DeepReadonly<T>>;
|
|
49
|
-
getState: () => T;
|
|
29
|
+
updateUrl: (value?: Partial<T> | Partial<DeepReadonly<T>> | ((currState: T) => T)) => void;
|
|
30
|
+
getState: () => DeepReadonly<T>;
|
|
50
31
|
};
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
32
|
+
/**
|
|
33
|
+
* NextJS hook. Returns `state`, `updateState`, and `updateUrl` functions
|
|
34
|
+
*
|
|
35
|
+
* @param {JSONCompatible<T>} [defaultState] Fallback (default) values for state
|
|
36
|
+
* @param {?SearchParams<T>} [searchParams] searchParams from Next server component
|
|
37
|
+
*
|
|
38
|
+
* * Example:
|
|
39
|
+
* ```ts
|
|
40
|
+
* export const form = { name: '', age: 0 };
|
|
41
|
+
* const { state, updateState, updateUrl } = useUrlState({ defaultState: form });
|
|
42
|
+
* // for nextjs seerver components
|
|
43
|
+
* // const { state, updateState, updateUrl } = useUrlState({ defaultState: form, searchParams });
|
|
44
|
+
*
|
|
45
|
+
* updateState({ name: 'test' });
|
|
46
|
+
* // by default it's uses router.push with scroll: false
|
|
47
|
+
* updateUrl({ name: 'test' }, { replace: true, scroll: true });
|
|
48
|
+
* // similar to React.useState
|
|
49
|
+
* updateUrl(curr => ({ ...curr, name: 'test' }), { replace: true, scroll: true });
|
|
50
|
+
* ```
|
|
51
|
+
*
|
|
52
|
+
* * Github {@link https://github.com/asmyshlyaev177/state-in-url/tree/main/packages/urlstate/next/useUrlState#api}
|
|
53
|
+
*/
|
|
54
|
+
export declare function useUrlState<T extends JSONCompatible>({ defaultState, searchParams, }: {
|
|
55
|
+
defaultState: T;
|
|
56
|
+
searchParams?: object;
|
|
54
57
|
replace?: boolean;
|
|
55
|
-
}
|
|
56
|
-
|
|
58
|
+
}): {
|
|
59
|
+
state: DeepReadonly<T>;
|
|
60
|
+
updateState: (value: Partial<T> | Partial<DeepReadonly<T>> | ((currState: T) => T)) => void;
|
|
61
|
+
updateUrl: (value?: Partial<T> | Partial<DeepReadonly<T>> | ((currState: T) => T)) => void;
|
|
62
|
+
getState: () => DeepReadonly<T>;
|
|
63
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{useRouter as t,useSearchParams as e}from"next/navigation";import
|
|
1
|
+
import{useRouter as t,useSearchParams as e}from"next/navigation";import a from"react";import{parseSsrQs as r}from"../parseSsrQs.mjs";import{useUrlStateBase as s}from"../../useUrlStateBase/useUrlStateBase.mjs";function c(c,l){const{_defaultState:n,_searchParams:u,_replace:o}=function(t,e){const a="defaultState"in t?t.defaultState:t,r="defaultState"in t?t.searchParams:e,s="defaultState"in t&&(t.replace??!0);return{_defaultState:a,_searchParams:r,_replace:s}}(c,l),f=t(),{state:i,updateState:m,updateUrl:p,getState:S}=s(n,f,u),d=a.useCallback(((t,e)=>{const a={scroll:!1,replace:o,...e};p(t,a)}),[p,o]),_=e();return a.useEffect((()=>{const t=Object.keys(n),e=Object.fromEntries([..._.entries()].filter((([e])=>t.includes(e))));m(r(e,n))}),[_]),{updateState:m,updateUrl:d,state:i,getState:S}}export{c as useUrlState};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import t from"react";import{stateMap as r,subscribers as e}from"../subscribers.mjs";import{useInsertionEffect as n}from"../useInsertionEffect.mjs";import{isSSR as c,isEqual as u}from"../utils.mjs";function s(s,o){const f=t.useRef(s),[i,a]=t.useState((()=>{if(c())return o?o?.():f.current;const t=
|
|
1
|
+
import t from"react";import{stateMap as r,subscribers as e}from"../subscribers.mjs";import{useInsertionEffect as n}from"../useInsertionEffect.mjs";import{isSSR as c,isEqual as u}from"../utils.mjs";function s(s,o){const f=t.useRef(s),[i,a]=t.useState((()=>{if(c())return o?o?.():f.current;const t=r.get(f.current);if(t)return t;{const t=o?.()||f.current;return r.set(f.current,t),t}})),m=t.useCallback((t=>{const n=r.get(f.current);if("function"==typeof t){const c=t(n);if(u(n,c))return;r.set(f.current,c),e.get(f.current).forEach((t=>{t()}))}else{const c={...n,...t};if(u(n,c))return;r.set(f.current,c),e.get(f.current).forEach((t=>{t()}))}}),[]);n((()=>{const t=e.add(f.current,(()=>{a(r.get(f.current)||f.current)}));return()=>{t()}}),[]);return{state:i,getState:t.useCallback((()=>r.get(f.current)||f.current),[]),setState:m}}export{s as useSharedState};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import t from"react";import{parseSsrQs as e}from"../next/parseSsrQs.mjs";import{useInsertionEffect as n}from"../useInsertionEffect.mjs";import{useSharedState as o}from"../useSharedState/useSharedState.mjs";import{useUrlEncode as r}from"../useUrlEncode/useUrlEncode.mjs";import{isSSR as s}from"../utils.mjs";function a(a,
|
|
1
|
+
import t from"react";import{parseSsrQs as e}from"../next/parseSsrQs.mjs";import{useInsertionEffect as n}from"../useInsertionEffect.mjs";import{useSharedState as o}from"../useSharedState/useSharedState.mjs";import{useUrlEncode as r}from"../useUrlEncode/useUrlEncode.mjs";import{isSSR as s}from"../utils.mjs";function a(a,m,u){const{parse:w,stringify:f}=r(a),{state:l,getState:d,setState:h}=o(a,(()=>s()?e(function(t,e){const n=Object.keys(t),o=Object.fromEntries(Object.entries(e||{}).filter((([t])=>n.includes(t))));return o}(a,u),a):w(c(a))));n((()=>{const t=()=>{const t=w(c(a));h(t)};return window.addEventListener(i,t),()=>{window.removeEventListener(i,t)}}),[h]);const p=t.useCallback(((t,e)=>{const n=`${window.location.pathname}${window.location.search}${window.location.hash}`,o="function"==typeof t,r=function(t){const e=Object.keys(t),n=window.location.search,o=new URLSearchParams(n),r=new URLSearchParams;return o.forEach(((t,n)=>!e.includes(n)&&r.set(n,t))),r}(a),s=o?t(d()):t?{...d(),...t}:d(),c=f(s,r);h(s);const i=`${window.location.pathname}${c.length?"?":""}${c}${window.location.hash}`;if(n!==i){const{replace:t,...n}=e||{};m[t?"replace":"push"](i,{...n})}}),[m,f,d]);return{updateState:h,updateUrl:p,state:l,getState:d}}function c(t){const e=new URLSearchParams(window.location.search),n=Object.keys(t),o=new URLSearchParams;return[...e.entries()].filter((([t])=>n.includes(t))).forEach((([t,e])=>o.set(t,e))),o.toString()}const i="popstate";export{a as useUrlStateBase};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "state-in-url",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"description": "Library to store state in browser URL, includes hook for NextJS, hook for pure React, and low level helpers.",
|
|
5
5
|
"homepage": "https://github.com/asmyshlyaev177/state-in-url#readme",
|
|
6
6
|
"keywords": [
|
|
@@ -120,7 +120,7 @@
|
|
|
120
120
|
]
|
|
121
121
|
},
|
|
122
122
|
"test:int": {
|
|
123
|
-
"command": "playwright test
|
|
123
|
+
"command": "playwright test --project=chromium --retries=2",
|
|
124
124
|
"dependencies": [
|
|
125
125
|
"example:react"
|
|
126
126
|
]
|
|
@@ -229,8 +229,8 @@
|
|
|
229
229
|
"@rollup/plugin-node-resolve": "^15.2.3",
|
|
230
230
|
"@rollup/plugin-terser": "^0.4.4",
|
|
231
231
|
"@rollup/plugin-typescript": "^11.1.6",
|
|
232
|
-
"@testing-library/dom": "^10.
|
|
233
|
-
"@testing-library/jest-dom": "^6.4.
|
|
232
|
+
"@testing-library/dom": "^10.4.0",
|
|
233
|
+
"@testing-library/jest-dom": "^6.4.8",
|
|
234
234
|
"@testing-library/react": "^16.0.0",
|
|
235
235
|
"@testing-library/react-hooks": "^8.0.1",
|
|
236
236
|
"@types/glob": "^8.1.0",
|