Skip to content

Commit

Permalink
Version 0.1.0 (#13)
Browse files Browse the repository at this point in the history
* WIP api update

* WIP change of name and api

* Build fix

* WIP docs update

* More fixes

* docs(changeset): Releasing v0.1.0

* Dependency update + cleanup

* docs(changeset): Rebrand to sp-hooks + more functional approach.
  • Loading branch information
bring-shrubbery authored Mar 19, 2024
1 parent f55bd4f commit 79e7170
Show file tree
Hide file tree
Showing 55 changed files with 4,180 additions and 3,703 deletions.
9 changes: 9 additions & 0 deletions .changeset/lemon-roses-carry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"@sp-hooks/tsconfig": minor
"@sp-hooks/prettier-config": minor
"@sp-hooks/react": minor
"@sp-hooks/eslint-config": minor
"@sp-hooks/next": minor
---

Releasing v0.1.0
9 changes: 9 additions & 0 deletions .changeset/quick-pears-mate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"@sp-hooks/tsconfig": minor
"@sp-hooks/prettier-config": minor
"@sp-hooks/react": minor
"@sp-hooks/eslint-config": minor
"@sp-hooks/next": minor
---

Rebrand to sp-hooks + more functional approach.
2 changes: 1 addition & 1 deletion .github/renovate.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"extends": ["config:base"],
"packageRules": [
{
"matchPackagePatterns": ["^@use-search-params-state/"],
"matchPackagePatterns": ["^@sp-hooks/"],
"enabled": false
}
],
Expand Down
47 changes: 27 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,35 +1,38 @@
# use-search-params-state
# Search Params Hooks

[![build](https://github.com/bring-shrubbery/use-search-params-state/actions/workflows/ci.yml/badge.svg)](https://github.com/bring-shrubbery/use-search-params-state/actions/workflows/ci.yml)
[![build](https://github.com/bring-shrubbery/sp-hooks/actions/workflows/ci.yml/badge.svg)](https://github.com/bring-shrubbery/sp-hooks/actions/workflows/ci.yml)

## Features

- 🚀 `useState` hook that syncs the state with URL Search Params.
- 😌 Easily sync state to the URL Search Params and back again.
- 💪 Use your own state manager.
- 🤓 Keeps URL clean by automatically removing default values.
- 😳 React Server Components ready.
- 🚀 Next.js integration.
- 🤯 Full TypeScript support.
- 😇 Integrations for SvelteKit/Solid.js coming soon.
- ⚡️ Accepts Zod schema for validation and parsing (WIP).
- 😳 Built for React, with Next.js integration available.
- 😇 Integrations for SvelteKit/Astro coming soon.

## Packages

| Package | Latest Version |
| ------------------------------ | ----------------------------------------------------------------------------- |
| @use-search-params-state/react | ![react-npm](https://img.shields.io/npm/v/%40use-search-params-state%2Freact) |
| @use-search-params-state/next | ![next-npm](https://img.shields.io/npm/v/%40use-search-params-state%2Fnext) |
| Package | Latest Version |
| ----------------- | -------------------------------------------------------------- |
| @usps-hooks/react | ![react-npm](https://img.shields.io/npm/v/%40sp-hooks%2Freact) |
| @usps-hooks/next | ![next-npm](https://img.shields.io/npm/v/%40sp-hooks%2Fnext) |

## Getting Started

### Step 1 ⭐️

Before we start, don't forget to star this repo, thanks!
Before we start, don't forget to star this repo and follow [@bring-shrubbery](https://github.com/bring-shrubbery), thanks!

### Next.js

`pnpm add @use-search-params-state/next`
`pnpm add @sp-hooks/next`

### React.js

`pnpm add @use-search-params-state/react`
`pnpm add @sp-hooks/react`

## Examples

Expand All @@ -38,18 +41,22 @@ Before we start, don't forget to star this repo, thanks!
Following example will render a button, which when clicked will toggle the button text between "hello" and "world". It will also update the search params to include the value, which means that after refreshing the page, the state will be preserved.

```tsx
import { useSearchParamsState } from "@use-search-params-state/next";
import { useState } from "react";

import { useObserveAndStore } from "@sp-hooks/next";

const Component = () => {
const [state, setState] = useSearchParamsState();
const [state, setState] = useState({ greeting: "hello" });

useObserveAndStore(state);

const handleClick = () => {
state.greeting === "hello"
? setState("greeting", "world")
: setState("greeting", "hello");
const greeting = state.greeting === "hello" ? "world" : "hello";

setState({ greeting });
};

return <button onClick={handleClick}>{state.greeting ?? "hello"}</button>;
return <button onClick={handleClick}>{state.greeting}</button>;
};
```

Expand All @@ -62,7 +69,7 @@ This example works in the same way functionally speaking. In the example above y
- TypeScript will understand that you have `greeting` parameter available, and will autosuggest it for you.

```tsx
import { useSearchParamsState } from "@use-search-params-state/next";
import { useSearchParamsState } from "@sp-hooks/next";

const Component = () => {
const [state, setState] = useSearchParamsState({
Expand All @@ -87,7 +94,7 @@ Here, before using the search params hook, we define Zod validation schema that

```tsx
"use client"
import { useSearchParamsState } from "@use-search-params-state/next";
import { useSearchParamsState } from "@sp-hooks/next";
import { z } from 'zod'

const SearchParamsSchema = z.object({
Expand Down
2 changes: 1 addition & 1 deletion SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@ The project is currently in the pre-release version. No security updates are pro

## Reporting a Vulnerability

If you find a vulnerability in this project, please create a ticket in the [Github repository](https://github.com/bring-shrubbery/use-search-params-state)https://github.com/bring-shrubbery/use-search-params-state.
If you find a vulnerability in this project, please create a ticket in the [Github repository](https://github.com/bring-shrubbery/sp-hooks)https://github.com/bring-shrubbery/sp-hooks.
21 changes: 15 additions & 6 deletions apps/docs/astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,33 @@ import { defineConfig } from "astro/config";

// https://astro.build/config
export default defineConfig({
site: "https://use-search-params-state.vercel.app/",
site: "https://sp-hooks.js.org/",
integrations: [
starlight({
title: "use-search-params-state docs",
title: "Search Params Hooks",
social: {
github: "https://github.com/bring-shrubbery/use-search-params-state",
github: "https://github.com/bring-shrubbery/sp-hooks",
discord: "https://discord.gg/fnp5zwCczT",
},
sidebar: [
{
label: "Getting started",
items: [],
items: [
{ label: "Introduction", link: "/getting-started/introduction/" },
{ label: "Starting with React", link: "/getting-started/react/" },
{ label: "Starting with Next.js", link: "/getting-started/nextjs/" },
],
},
{
label: "Guides",
items: [
// Each item here is one entry in the navigation menu.
{ label: "Example Guide", link: "/guides/example/" },
{ label: "Basic", link: "/guides/basic/" },
{ label: "With default values", link: "/guides/default-values" },
{ label: "React Server Components (in Next.js)", link: "/guides/rsc" },
{ label: "With validation (wip)", link: "/guides/validation" },
{ label: "With Jotai", link: "/guides/jotai" },
{ label: "With Zustand", link: "/guides/zustand" },
{ label: "With Redux", link: "/guides/redux" }
],
},
{
Expand Down
16 changes: 8 additions & 8 deletions apps/docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@
"with-env": "dotenv -e ../../.env --"
},
"dependencies": {
"@astrojs/check": "^0.3.1",
"@astrojs/starlight": "^0.12.0",
"@astrojs/check": "^0.5.9",
"@astrojs/starlight": "^0.21.1",
"@astrojs/starlight-tailwind": "^2.0.1",
"@astrojs/tailwind": "^5.0.0",
"astro": "^3.4.3",
"dotenv-cli": "^7.3.0",
"sharp": "^0.32.5",
"tailwindcss": "^3",
"typescript": "^5.2.2"
"@astrojs/tailwind": "^5.1.0",
"astro": "^4.5.6",
"dotenv-cli": "^7.4.1",
"sharp": "^0.33.2",
"tailwindcss": "^3.4.1",
"typescript": "^5.4.2"
}
}
22 changes: 22 additions & 0 deletions apps/docs/src/content/docs/getting-started/introduction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
title: Introduction
description: Why and how to use `@sp-hooks` packages.
---

## The problem

With the rise of server-sided state management solutions, we find ourselves in a situation where we not only need to manage state on the client side, but also sync it with the server.

Here's a situation: you need to implement an e-commerce browse page, where you can filter/sort/paginate products. You store user's filters in a regular React `useState` hook, then make a client sided request to get the products.

Now, there's a little problem, you get a number of delays, because of all the round trips to the server. React Server Components solve this problem by removing as many of the round trips as possible, leaving you with essentially two things: API call from your frontend's backend to the API backend, and the time it takes to stream in HTML into your React application.

Here lies the state synchronisation problem. When prerendering the page on the server side, there's no way to access state of the `useState` hook. The best way to solve this at the moment is through the use of URL search params, which can be accessed on the server side, while each route getting its own state.

This means that for the route like `/products?filter=price&sort=asc&page=2`, you can get the state of the filters, sort and page, and use it to render the page on the server side.

## The solution

In production, the code to manage the state of the URL search params becomes unmanageable quite fast. You need to parse state from the URL, update the state, and then update the URL again. This is where `@sp-hooks` come in.

`@sp-hooks` packages are a set of hooks that simplify management of state in a way that is both client and server side friendly. They are designed to be used with Next.js, but can be used with any React application.
10 changes: 10 additions & 0 deletions apps/docs/src/content/docs/getting-started/nextjs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
title: Installing for Next.js applications.
description: How to install the `@sp-hooks` packages in a Next.js application.
---

## Installation

```sh
npm install @sp-hooks/next
```
10 changes: 10 additions & 0 deletions apps/docs/src/content/docs/getting-started/react.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
title: Installing for generic React applications.
description: How to install the `@sp-hooks` packages in a generic React application.
---

## Installation

```sh
npm install @sp-hooks/react
```
63 changes: 63 additions & 0 deletions apps/docs/src/content/docs/guides/basic.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
---
title: Basic usage with Next.js.
description: The bare minimum example of sp-hooks.
---

The `@sp-hooks` packages are designed to be used in conjunction with the state management solution of your choice. They are designed to be used with Next.js, but can be used with any React application.

## The `useObserveAndStore` hook

The first thing you will want to do with `@sp-hooks` is to observe and store the state of your component. This is done with the `useObserveAndStore` hook.

This hook will observe the state of your component, and store it in the URL search params. This means on every change of the state, the URL will be updated to reflect the new state.

```tsx
import { useObserveAndStore } from "@sp-hooks/next";

const ClientComponent = () => {
const [state, setState] = useState();

useObserveAndStore(state);

const handleClick = () => {
setState({
hello: state.hello === "hello" ? "world" : "there"
});
};

return <button onClick={handleClick}>{state.hello}</button>;
};
```

The `useObserveAndStore` hook expects you to pass an object with the following type: `Record<string, Value | Value[]>`, where `type Value = string | number | boolean | BigInt | Date`.

> Note: Since we are serializing the state to the URL, we are limited to the types that can be serialized to a string. This means that you cannot store complex objects in the URL.
## The `searchParamsToObject` function

If you try the code above, you will notice that the stae is updated in React and in the URL. But if you refresh the page, the state will be lost. This is because we are not reading the state from the URL.

The `searchParamsToObject` function is a utility function that will convert the URL search params to an object.

```tsx
import { useSearchParams } from "next/navigation";
import { searchParamsToObject, useObserveAndStore } from "@sp-hooks/next";

const ClientComponent = () => {
const searchParams = useSearchParams();

const [state, setState] = useState(searchParamsToObject(searchParams));

useObserveAndStore(state);

const handleClick = () => {
setState({
hello: state.hello === "hello" ? "world" : "there"
});
};

return <button onClick={handleClick}>{state.hello}</button>;
};
```

Now when you refresh the page, the state will be read from the URL and passed as initial state of `useState` hook. The button will reflect the state.
47 changes: 47 additions & 0 deletions apps/docs/src/content/docs/guides/default-values.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
---
title: Default Values
description: How to set default values for your state.
---

When using default values you have to do a couple of things:

- Provide default values to your state manager.
- Provide the same default values to `useObserveAndStore` hook, if you want to remove default values from search params when they are set to the default value.

## Example

```tsx
import { useObserveAndStore } from "@sp-hooks/next";

const ClientComponent = () => {
const [state, setState] = useState({
greeting: "hello",
});

useObserveAndStore(state, {
defaultValues: {
greeting: "hello",
},
});

return <button>{state.greeting}</button>;
}
```

## A cleaner version

```tsx
import { useObserveAndStore } from "@sp-hooks/next";

const defaultValues = {
greeting: "hello",
};

const ClientComponent = () => {
const [state, setState] = useState(defaultValues);

useObserveAndStore(state, { defaultValues });

return <button>{state.greeting}</button>;
}
```
11 changes: 0 additions & 11 deletions apps/docs/src/content/docs/guides/example.md

This file was deleted.

29 changes: 29 additions & 0 deletions apps/docs/src/content/docs/guides/jotai.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
---
title: Basic usage with Jotai and Next.js
description: The bare minimum example of using sp-hooks with Jotai and Next.js.
---

## Example

```tsx
import { useObserveAndStore } from "@sp-hooks/next";
import { atom, useAtom } from "jotai";

const stateAtom = atom({
hello: "hello"
});

const ClientComponent = () => {
const [state, setState] = useAtom(stateAtom);

useObserveAndStore(state);

const handleClick = () => {
setState({
hello: state.hello === "hello" ? "world" : "there"
});
};

return <button onClick={handleClick}>{state.hello}</button>;
};
```
Loading

0 comments on commit 79e7170

Please sign in to comment.