Skip to content

Commit

Permalink
Merge pull request #10 from asmyshlyaev177/react-router
Browse files Browse the repository at this point in the history
`useUrlState` hook for React-router
  • Loading branch information
asmyshlyaev177 authored Sep 30, 2024
2 parents 6fab20c + 40209f6 commit 535e0bf
Show file tree
Hide file tree
Showing 134 changed files with 2,177 additions and 1,105 deletions.
9 changes: 9 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
typings.d.ts
package.json
playwright.config.ts
rollup.config.js
.eslintrc.cjs
*.test.ts
*.test.tsx
*.spec.ts
*.spec.ts
testUtils.ts
dist
exportsTest.ts
35 changes: 18 additions & 17 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
module.exports = {
root: true,
extends: ["plugin:maintainable/recommended"],
plugins: ["maintainable"],
parserOptions: {
project: './tsconfig.eslint.json',
extends: ['plugin:maintainable/recommended'],
plugins: ['maintainable', "react-hooks"],
parserOptions: {
project: './tsconfig.json',
tsconfigRootDir: __dirname,
},
// ignores: [
Expand All @@ -12,22 +12,23 @@ module.exports = {
// "*.env.*",
// ],
rules: {
"max-len": "off",
"complexity": ["error", 12],
'max-len': 'off',
complexity: ['error', 12],
},
overrides: [
{
"files": ["packages/example-nextjs14/src/app/Form-for-test.tsx", "packages/example-nextjs15/src/app/Form-for-test.tsx"],
"rules": {
"max-lines-per-function": ["error", 200]
}
files: [
'Form-for-test.tsx',
],
rules: {
'max-lines-per-function': ['error', 200],
},
},
{
"files": ["packages/example-react-router6/**/*"],
"rules": {
"@typescript-eslint/no-unused-vars": "warn"
}
}
]

files: ['packages/example-react-router6/**/*'],
rules: {
'@typescript-eslint/no-unused-vars': 'warn',
},
},
],
};
6 changes: 6 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ jobs:
path: |
./node_modules
./dist
./packages/example-react-router6/dist
./packages/example-react-router6/package.json
./packages/example-react/dist
./packages/example-react/package.json
./packages/example-nextjs14/package.json
Expand Down Expand Up @@ -133,6 +135,8 @@ jobs:
path: |
./node_modules
./dist
./packages/example-react-router6/dist
./packages/example-react-router6/package.json
./packages/example-react/dist
./packages/example-react/package.json
./packages/example-nextjs14/package.json
Expand Down Expand Up @@ -181,6 +185,8 @@ jobs:
path: |
./node_modules
./dist
./packages/example-react-router6/dist
./packages/example-react-router6/package.json
./packages/example-react/dist
./packages/example-react/package.json
./packages/example-nextjs14/package.json
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
node_modules
.next
dist
/dist/
/test-results/
/playwright-report/
/blob-report/
Expand Down
3 changes: 0 additions & 3 deletions .husky/commit-msg
Original file line number Diff line number Diff line change
@@ -1,4 +1 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

npx --no-install commitlint --edit "$1"
3 changes: 0 additions & 3 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -1,4 +1 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

npx lint-staged
3 changes: 0 additions & 3 deletions .husky/prepare-commit-msg
Original file line number Diff line number Diff line change
@@ -1,4 +1 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

exec < /dev/tty && npx cz --hook || true
4 changes: 3 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ Make sure that what you trying to fix really a bug, or if adding feature that is
2. Write code! Add some feature or fix bug.

3. Check that all tests passed(unit and e2e) and add tests for your code.
You can run unit tests with `npm run test:unit` and cypress tests `npm run test`
Run all tests witn `npm run test`
You can run tests separately with `npm run test:unit` and tests `npm run test:int`
Use `npm run kill` if some processes hang.

4. Update readme and example (if needed)

Expand Down
137 changes: 112 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,20 +59,24 @@ Add a ⭐️ and <a href="https://github.com/asmyshlyaev177" target="_blank">fol
## Table of content

- [Installation](#installation)
- [`useUrlState` for Next.js](#useurlstate-hook-for-nextjs)
- [`useUrlStateBase` for other routers](#useurlstatebase-hook-for-others-routers)
- [`useSharedState` hook for React.js/Next.js](#usesharedstate-hook-for-reactjs)
- [`useUrlEncode` for React.js](#useurlencode-hook-for-reactjs)
- [`encodeState` and `decodeState` for pure JS usage](#encodestate-and-decodestate-helpers)
- [auto sync state with url](#auto-sync-state)
- [Low-level `encode` and `decode` functions](#encode-and-decode-helpers)
- [useUrlState hook](#useurlstate)
- - [Next.js](#useurlstate-hook-for-nextjs)
- - [React-Router](#useurlstate-hook-for-react-router)
- [Other helpers](#other-hooks-and-helpers)
- - [`useUrlStateBase` for other routers](#useurlstatebase-hook-for-others-routers)
- - [`useSharedState` hook for React.js/Next.js](#usesharedstate-hook-for-reactjs)
- - [`useUrlEncode` for React.js](#useurlencode-hook-for-reactjs)
- - [`encodeState` and `decodeState` for pure JS usage](#encodestate-and-decodestate-helpers)
- - [Low-level `encode` and `decode` functions](#encode-and-decode-helpers)
- [Best practices](#best-practices)
- [Gothas](#gothas)
- [Roadmap](#roadmap)
- [Contact & Support](#contact--support)
- [Changelog](#changelog)
- [License](#license)
- [Inspiration](#inspiration)
- - [Gothas](#gothas)
- [Other](#other)
- - [Roadmap](#roadmap)
- - [Contributing](#contribute-andor-run-locally)
- - [Contact & Support](#contact--support)
- - [Changelog](#changelog)
- - [License](#license)
- - [Inspiration](#inspiration)

## installation

Expand All @@ -92,12 +96,14 @@ pnpm add state-in-url
In `tsconfig.json` in `compilerOptions` set `"moduleResolution": "Bundler"`, or`"moduleResolution": "Node16"`, or `"moduleResolution": "NodeNext"`.
Possibly need to set `"module": "ES2022"`, or `"module": "ESNext"`

# useUrlState

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

## useUrlState hook for Next.js

[Docs](packages/urlstate/next/useUrlState#api)

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

### Usage examples

#### Basic
Expand Down Expand Up @@ -334,6 +340,90 @@ function SettingsComponent() {
}
```

## useUrlState hook for React-Router

API is same as for Next.js version, except can pass options from [NavigateOptions](https://github.com/remix-run/react-router/blob/bc693ed9f39170bda13b9e1b282fb8e9d5925f66/packages/react-router/lib/context.ts#L99) type.

[Docs](packages/urlstate/react-router/useUrlState#api)


### Example

```typescript
export const form: Form = {
name: '',
age: undefined,
'agree to terms': false,
tags: [],
};

type Form = {
name: string;
age?: number;
'agree to terms': boolean;
tags: { id: string; value: { text: string; time: Date } }[];
};

```

```typescript
import { useUrlState } from 'state-in-url/react-router';

import { form } from './form';

function TagsComponent() {
const { state, updateUrl } = useUrlState({ defaultState: form });

const onChangeTags = React.useCallback(
(tag: (typeof tags)[number]) => {
updateUrl((curr) => ({
...curr,
tags: curr.tags.find((t) => t.id === tag.id)
? curr.tags.filter((t) => t.id !== tag.id)
: curr.tags.concat(tag),
}));
},
[updateUrl],
);

return (
<div>
<Field text="Tags">
<div className="flex flex-wrap gap-2">
{tags.map((tag) => (
<Tag
active={!!state.tags.find((t) => t.id === tag.id)}
text={tag.value.text}
onClick={() => onChangeTags(tag)}
key={tag.id}
/>
))}
</div>
</Field>
</div>
);
}

const tags = [
{
id: '1',
value: { text: 'React.js', time: new Date('2024-07-17T04:53:17.000Z') },
},
{
id: '2',
value: { text: 'Next.js', time: new Date('2024-07-18T04:53:17.000Z') },
},
{
id: '3',
value: { text: 'TailwindCSS', time: new Date('2024-07-19T04:53:17.000Z') },
},
];
```

[Example code](packages/example-react-router6/src/Form-for-test.tsx)

# Other hooks and helpers

## `useUrlStateBase` hook for others routers

Hooks to create your own `useUrlState` hooks with other routers, e.g. react-router or tanstack router.
Expand Down Expand Up @@ -369,7 +459,7 @@ function SettingsComponent() {

[Docs](packages/urlstate/encoder/README.md)

## Best Practices
# Best Practices

- Define your state shape as a constant
- Use TypeScript for enhanced type safety and autocomplete
Expand All @@ -384,32 +474,29 @@ function SettingsComponent() {
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>
3. Tested with `next.js` 14/15 with app router, no plans to support pages.

## Run locally
# Other

Clone this repo, run `npm install` and
## Contribute and/or run locally

```sh
npm run dev
```
See [Contributing doc](CONTRIBUTING.md)

Go to [localhost:3000](http://localhost:3000)

## Roadmap

- [x] hook for `Next.js`
- [ ] hook for 'react-router`
- [x] hook for 'react-router`
- [ ] hook for 'remix`
- [ ] hook for store state in hash ?

## Contact & Support

- Create a [GitHub issue](https://github.com/asmyshlyaev177/state-in-url/issues) for bug reports, feature requests, or questions

## [Changelog](https://github.com/asmyshlyaev177/state-in-url/blob/main/CHANGELOG.md)
## [Changelog](CHANGELOG.md)

## License

This project is licensed under the [MIT license](https://github.com/asmyshlyaev177/state-in-url/blob/main/LICENSE).
This project is licensed under the [MIT license](LICENSE).

## Inspiration

Expand Down
1 change: 0 additions & 1 deletion dist/constants/constants.mjs

This file was deleted.

1 change: 0 additions & 1 deletion dist/constants/index.mjs

This file was deleted.

1 change: 0 additions & 1 deletion dist/encodeState/encodeState.mjs

This file was deleted.

1 change: 0 additions & 1 deletion dist/encodeState/index.mjs

This file was deleted.

1 change: 0 additions & 1 deletion dist/encoder/encoder.mjs

This file was deleted.

1 change: 0 additions & 1 deletion dist/encoder/index.mjs

This file was deleted.

1 change: 0 additions & 1 deletion dist/index.mjs

This file was deleted.

1 change: 0 additions & 1 deletion dist/next/index.mjs

This file was deleted.

1 change: 0 additions & 1 deletion dist/next/parseSPObj.mjs

This file was deleted.

1 change: 0 additions & 1 deletion dist/next/useUrlState/index.mjs

This file was deleted.

1 change: 0 additions & 1 deletion dist/next/useUrlState/useUrlState.mjs

This file was deleted.

8 changes: 0 additions & 8 deletions dist/shared/components/Button.d.ts

This file was deleted.

7 changes: 0 additions & 7 deletions dist/shared/components/Field.d.ts

This file was deleted.

4 changes: 0 additions & 4 deletions dist/shared/components/Input.d.ts

This file was deleted.

3 changes: 0 additions & 3 deletions dist/shared/components/Refresh.d.ts

This file was deleted.

5 changes: 0 additions & 5 deletions dist/shared/components/Tag.d.ts

This file was deleted.

7 changes: 0 additions & 7 deletions dist/shared/components/Textarea.d.ts

This file was deleted.

5 changes: 0 additions & 5 deletions dist/shared/components/index.d.ts

This file was deleted.

Loading

0 comments on commit 535e0bf

Please sign in to comment.