graph-state is graph based state manager, designed for both simple and complex applications. Focused on work with many deep and dependence data.
Package | Version | Docs | Size |
---|---|---|---|
@graph-state/core |
|||
@graph-state/react |
|||
@graph-state/plugin-logger |
|||
@graph-state/plugin-ws |
|||
@graph-state/plugin-extend |
npm i @graph-state/core @graph-state/react
or
yarn add @graph-state/core @graph-state/react
App.tsx
import { useGraph } from '@graph-state/react'
import { createState } from '@graph-state/core'
const grapState = createState({
value: 150
})
const App = () => {
const [state, setState] = useGraph(grapState)
return <div>
<h1>{state.value}</h1>
<input type="text" value={state.value} onChange={(e) => setState({ value: e.target.value })}/>
</div>
}
const state = createState({
initialState: {
modal: 'about',
layers: []
}
})
state.subscribe(state, (data) => {
// state updates
})
state.resolve() // { modal: 'about', layers: [] }
// or state.resolve(state) or state.resolve(state.key)
state.mutate({
layers: [19]
})
state.resolve() // { modal: 'about', layers: [19] }
Graph state had few abstractions
_type
field._type:_id
of graphIs plain object with _type
const baseGraph = {
_type: 'Graph',
_id: 'any uniq id' // or id or use keying config
}
Is a manager of graphs with reactive updates.
import { createState } from '@graph-state/core'
const graphState = createState()
console.log(graphState)
/**
* _id: 'State uniq id'
* _type: 'Instance'
* ...other methods
*/
Signature
mutate(updatedGraph)
mutate(graphKey, updatedGraph)
mutate(graphKey, (prevGraph) => updatedGrap)
import { createState } from '@graph-state/core'
const graphState = createState()
const user = {
_type: 'User',
_id: 'usernameOne',
name: 'James'
}
graphState.mutate(user)
// Now graphState has user, you can read him
graphState.resolve(user).name // James
// Change name
graphState.mutate({
...user,
name: 'Not James'
})
graphState.resolve(user).name // Not James
// Change by key
graphState.mutate('User:usernameOne', {
name: 'Alie',
gender: 'female' // Add new property
})
graphState.resolve(user)
/**
* _type: 'User'
* _id: 'usernameOne'
* name: 'James'
* gender: 'female'
*/
// Mutate with conditional
graphState.mutate('User:usernameOne', prev => ({
someProp: prev.gender === 'female' ? 'value one' : 'value two'
}))
By default, state deep merged. You don`t need spread every update. You can use {replace: true} on mutation for replace state.
replace
- force replace object or array (default: false)dedup
- skip duplicate links in array (default: true)
state.mutate(
{ ...some data },
{
replace: true,
dedup: false
}
)
import { createState } from '@graph-state/core'
const userOne = {
_type: 'User',
_id: 'id',
name: 'James'
}
const userTwo = {
_type: 'User',
_id: 'id2',
name: 'Barb'
}
const graphState = createState({initialState: [userOne, userTwo]})
graphState.resolve(userOne).name // James
graphState.resolve('User:id2').name // Barb
graphState.inspectFields('User')
/**
* User:id
* User:id2
*/
deep
- resolve all nested graphs (default: false)
import { createState } from '@graph-state/core'
const userGraph = {
_type: 'User',
_id: 'id',
name: 'James'
}
const graphState = createState({initialState: userGraph})
graphState.subscribe(userGraph, (nextState) => {
/**
* _type
* _id
* name: Stef
*/
})
graphState.mutate({
...userGraph,
name: 'Stef'
})
import { createState } from '@graph-state/core'
const userGraph = {
_type: 'User',
_id: 'id',
name: 'James'
}
const graphState = createState({initialState: userGraph})
graphState.subscribe(nextState => {
// Call every state update
})
graphState.mutate({
...userGraph,
name: 'Stef'
})
import { createState } from '@graph-state/core'
const user = {
_type: 'User',
_id: 'id',
name: 'Vlad'
}
const post = {
_type: 'Post',
_id: 'id',
title: 'Some post title',
auhtor: user
}
const graphState = createState({initialState: post})
graphState.subscribe(user, (nextState) => {
/**
* user will be updated if parent was chnaged
*
* _type
* _id
* name: Stef
*/
})
graphState.mutate({
...post,
title: 'Some different title'
})
An example above we create nested graph. You can use any nested level for your state. Inside state will be created link for graphs.
Document
posts
post (_id one)
author (_id someUser)
post
author (_id otherUser)
post
author (_id someUser) // Same user
You can mutate user in one place and him will update in all posts.
import { createState } from '@graph-state/core'
const loggerPlugin = (graphState) => {
const originalMutate = graphState.mutate
graphState.mutate = (...args) => {
const {entityKey, data} = getArgumentsForMutate(...args)
console.log(`Graph ${entityKey} was updated.`)
originalMutate(...args)
}
}
const graphState = createState({
plugins: [loggerPlugin]
})
Sometimes we need skip recursive iterate and save link on initial data.
const Title = <h1>Hello</h1>
const state = createState({
initialState: {
jsxNode: Title
},
skip: [() => /*check if jsx*/]
})
state.resolve().jsxNode === Title // true
graphState.keyOfEntity({
_type: 'User',
_id: 'id'
}) // User:id
graphState.entityOfKey('User:id')
/**
* _type: 'User',
* _id: 'id'
*/