@watch-state/react
State manager for React 18+ based on watch-state
Install
npmnpm i @watch-state/react
Usage
useWatch
You can observe only function components, byuseWatch
hook.```typescript jsx import { State } from 'watch-state' import { useWatch } from '@watch-state/react'
const show = new State(false) const toggleShow = () => show.value = !show.value
const AsideMenuButton = () => (
onClick={toggleShow}
/>
)const AsideMenu = () => { const isShow = useWatch(show)
return isShow ? (
<div>Aside Menu</div>
) : null
}
#### useWatcher
You can observe only function components, by `useWatcher` hook.
```typescript jsx
import { State } from 'watch-state'
import { useWatcher } from '@watch-state/react'
const show = new State(false)
const toggleShow = () => show.value = !show.value
const AsideMenuButton = () => (
<button
onClick={toggleShow}
/>
)
const AsideMenu = () => {
const isShow = useWatcher(() => show.value)
// here is the difference ^^^^^^^^^^^^^^^
return isShow ? (
<div>Aside Menu</div>
) : null
}
useNewState
useNewState
helps to create a State
inside react component.```typescript jsx import { Observable } from 'watch-state' import { useWatch, useNewState } from '@watch-state/react' import { useEffect } from "react";
interface ChildProps { value: Observable }
const Parent = () => { console.log('Parent creates State once');
const state = useNewState(0)
useEffect(() => {
const t = setInterval(() => {
state.value++
}, 1000)
return () => {
clearInterval(t)
}
}, )return (
<Test value={state}/>
)
}const Test = ({ value }: ChildProps) => { console.log('Test renders once and provides value to Child', value);
return (
<Child value={value}/>
)
}const Child = ({ value }: ChildProps) => { console.log('Child renders on value canges', value);
const currentValue = useWatch(value)
return (
<div>
{currentValue}
</div>
)
}
#### useNewCache
`useNewCache` helps to create a `Cache` inside a component.
```typescript jsx
import { State } from 'watch-state'
import { useWatch, useNewCache } from '@watch-state/react'
const name = new State('Mike')
const surname = new State('Deight')
const Parent = () => {
const fullName = useNewCache(() => `${name.value} ${surname.value[0]}.`)
// renders once
return <Child fullName={fullName} />
}
interface ChildProps {
fullName: Observable<string>
}
const Child = ({ fullName }: ChildProps) => {
const value = useWatch(fullName)
// renders when fullName canges
return <div>{value}</div>
}
useNewCache
also helps to combine props and Observable
inside a component.```typescript jsx import { State } from 'watch-state' import { useWatch, useNewCache } from '@watch-state/react'
const name = new State('Mike')
interface ParentProps { surname: string }
const Parent = ({ surname }: ParentProps) => { const fullName = useNewCache(() =>
${name.value} ${surname[0]}.
, surname)
// renders when surname changes
return
}interface ChildProps { fullName: Observable }
const Child = ({ fullName }: ChildProps) => { const value = useWatch(fullName) // renders when fullName canges return
{value}
}
You can use all features [watch-state](https://www.npmjs.com/search?q=%40watch-state) ecosystem.
`Cache` example:
```typescript jsx
import { State, Cache } from 'watch-state'
import { useWatch } from '@watch-state/react'
const name = new State('Mike')
const surname = new State('Deight')
const fullName = new Cache(() => `${name.value} ${surname.value[0]}.`)
const User = () => {
const value = useWatch(fullName)
return (
<>{value}</>
)
}
@watch-state/history-api example:
```typescript jsx import { useWatch } from '@watch-state/react' import { locationPath, historyPush } from '@watch-state/history-api'
const goTest = () => { historyPush('/test') }
const User = () => { const path = useWatch(locationPath)
return (
<button onClick={goTest}>
{path}
</button>
)
}
[@watch-state/async](https://www.npmjs.com/package/@watch-state/async) example:
```typescript jsx
import { useWatch, useWatcher } from '@watch-state/react'
import Async from '@watch-state/async'
const api = new Async(
() => fetch('/api/test')
.then(r => r.json())
)
const User = () => {
const value = useWatch(api)
const loading = useWatcher(() => api.loading)
const loaded = useWatcher(() => api.loaded)
const error = useWatcher(() => api.error)
if (error) {
return <div>Error!</div>
}
if (!loaded) {
return <div>Loading</div>
}
return (
<div className={loading && 'loading'}>
{value.some.fields}
</div>
)
}