-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
docs(store): rewrite readme and all of docs
- Loading branch information
1 parent
48845c4
commit 2fde198
Showing
12 changed files
with
883 additions
and
199 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,3 +11,4 @@ dist-ssr | |
server/dist | ||
public/dist | ||
.turbo | ||
coverage |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
# Async usage | ||
|
||
Davstack store can be combined with davstack service to manage async state. Here is an example of how to use davstack store with davstack service to manage async state. | ||
|
||
1. Export the trpc react query api utils from your trpc provider file | ||
|
||
```tsx | ||
export let apiUtils = null as unknown as ReturnType<typeof api.useUtils>; | ||
|
||
function InitApiClient() { | ||
const actualApiUtils = api.useUtils(); | ||
|
||
useEffect(() => { | ||
apiUtils = actualApiUtils; | ||
}, [actualApiUtils]); | ||
|
||
return null; | ||
} | ||
|
||
export function TRPCReactProvider(props: { children: React.ReactNode }) { | ||
// ... other code | ||
return ( | ||
<api.Provider client={trpcClient} queryClient={queryClient}> | ||
<QueryClientProvider client={queryClient}> | ||
{props.children} | ||
<InitApiClient /> | ||
</QueryClientProvider> | ||
</api.Provider> | ||
); | ||
} | ||
``` | ||
|
||
This allows you to access the api utils from anywhere in your app. | ||
|
||
2. Create a store that manages the async state | ||
|
||
```tsx | ||
import { store } from '@davstack/store'; | ||
|
||
export const notificationsStore = store({ | ||
subscription: null as PushSubscription | null, | ||
registration: null as ServiceWorkerRegistration | null, | ||
}) | ||
.computed((store) => ({ | ||
isSubscribed: () => Boolean(store.subscription), | ||
})) | ||
.extend((store) => { | ||
async function init() { | ||
const registration = await navigator.serviceWorker.ready; | ||
|
||
try { | ||
checkPushNotificationIsSupported(); | ||
|
||
const subscription = await registration.pushManager.getSubscription(); | ||
|
||
// use the api utils to make a request to the server | ||
await apiUtils.notification.checkSubscription.fetch({ | ||
endpoint: subscription.endpoint, | ||
}); | ||
|
||
store.subscription.set(subscription); | ||
} catch (error) { | ||
console.error('Error initializing subscription:', error); | ||
} | ||
} | ||
|
||
return { | ||
/** | ||
* Initializes the store, should only be place once in root layout | ||
*/ | ||
Init() { | ||
useEffect(() => { | ||
init(); | ||
}, []); | ||
|
||
return null; | ||
}, | ||
}; | ||
}); | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
import { Callout } from 'nextra/components'; | ||
|
||
# Defining Stores | ||
|
||
To create a store, you can use the `store()` function and pass in the initial state: | ||
|
||
```tsx | ||
import { store } from '@davstack/store'; | ||
|
||
const counterStore = store(0); | ||
``` | ||
|
||
Alternatively, you can use `store.state()` to define the initial state: | ||
|
||
```tsx | ||
const counterStore = store().state(0); | ||
``` | ||
|
||
<Callout type="info" emoji="ℹ️"> | ||
`store(initialState)` and `store.state(initialState)` are equivalent and can be used interchangeably. | ||
|
||
</Callout> | ||
|
||
## Defining Actions | ||
|
||
Actions are functions that modify the store's state. They can be defined using the `actions` method: | ||
|
||
```tsx | ||
const userStore = store() | ||
.state({ | ||
name: 'John', | ||
age: 25, | ||
}) | ||
.actions((store) => ({ | ||
incrementAge() { | ||
store.age.set(store.age.get() + 1); | ||
}, | ||
})); | ||
|
||
// calling actions | ||
userStore.incrementAge(); | ||
``` | ||
|
||
## Defining Computed Properties | ||
|
||
Computed properties are derived values that are automatically updated when the store's state changes. They can be defined using the `computed` method: | ||
|
||
```tsx | ||
const userStore = store() | ||
.state({ | ||
name: 'John', | ||
age: 25, | ||
}) | ||
.computed((store) => ({ | ||
fullName: () => `${store.name.get()} Doe`, | ||
})); | ||
|
||
// accessing computed properties | ||
const fullName = userStore.fullName.get(); | ||
``` | ||
|
||
<Callout type="info" emoji="ℹ️"> | ||
How do computed properties work? | ||
</Callout> | ||
|
||
- The "store" passed into the computed callback is a proxy. | ||
- When you call `store.computedValue.get()`, then the store will be passed to the computed function like normal. | ||
- When you call `store.computedValue.use()`, then the store passed to computed function will detect any `store.get()` calls inside the computed function, and will replace them with `store.use()` calls. | ||
- This means that the value will be re-evaluated whenever any of the dependencies change, but it does not currently cache the result. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
# Extensions | ||
|
||
Extensions allow you to assign any additional properties to the store, while keeping the store definition self-contained and reusable. | ||
|
||
Under the hood, `actions`, `computed` and `effects` all wrap around the `extend` method. | ||
|
||
However, you can also use `extend` directly to add any custom properties to the store, which don't direclty fit into the state, actions or computed properties. | ||
|
||
## Basic usage example | ||
|
||
```tsx | ||
import { store } from '@davstack/store'; | ||
|
||
const userStore = store() | ||
.state({ | ||
name: 'John', | ||
age: 25, | ||
}) | ||
.extend((store) => ({ | ||
isAdmin: false, | ||
})); | ||
|
||
// accessing the extension | ||
|
||
const isAdmin = userStore.isAdmin.get(); | ||
``` | ||
|
||
## Example usage with hooks | ||
|
||
```tsx | ||
|
||
const altStore = store({ | ||
searchTerm: '', | ||
}).extend((store) => ({ | ||
useFilteredBooks: () => { | ||
const searchTerm = store.searchTerm.use(); | ||
// use react query or any other data fetching library here | ||
|
||
}, | ||
|
||
``` | ||
## Example usage with components | ||
```tsx | ||
import { store } from '@davstack/store'; | ||
|
||
export const notificationsStore = store({ | ||
subscription: null as PushSubscription | null, | ||
registration: null as ServiceWorkerRegistration | null, | ||
}). | ||
.computed((store) => ({ | ||
isSubscribed: () => Boolean(store.subscription), | ||
})) | ||
.extend((store) => { | ||
async function init() { | ||
const registration = await navigator.serviceWorker.ready; | ||
|
||
try { | ||
checkPushNotificationIsSupported(); | ||
|
||
const subscription = await registration.pushManager.getSubscription(); | ||
|
||
if (!subscription) { | ||
console.log("No subscription found"); | ||
return; | ||
} | ||
|
||
|
||
await apiUtils!.notification.checkSubscription.fetch({ | ||
endpoint: subscription.endpoint, | ||
}); | ||
|
||
store.subscription.set(subscription); | ||
} catch (error) { | ||
console.error("Error initializing subscription:", error); | ||
} | ||
} | ||
|
||
return { | ||
/** | ||
* Initializes the store, should only be place once in root layout | ||
*/ | ||
Init() { | ||
useEffect(() => { | ||
init(); | ||
}, []); | ||
|
||
return null; | ||
} | ||
}; | ||
}); | ||
|
||
// app/layout.tsx | ||
import { notificationsStore } from './notificationsStore'; | ||
|
||
export default function Layout({ children }:{children: React.ReactNode}) { | ||
return ( | ||
<div> | ||
{children} | ||
<notificationsStore.Init> | ||
</div> | ||
); | ||
} | ||
|
||
|
||
``` |
Oops, something went wrong.