Package Exports
- mutoid
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (mutoid) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
Mutoid
Reactive library for state management, data fetching, caching (wip) with some utilities to use with React
Installation
To install the last version
yarn add mutoid rxjs fp-tsif you want to use io-ts decoder in data fetching
yarn add io-tsif you want also to use with react
yarn add react-dom reactNote rxjs, fp-ts, io-ts, react are a peer dependency for mutoid
State management
import * as MS from 'mutoid/state'
Create store
in ctor we use memoization
const appStore = MS.ctor(() => ({ name: 'appStore' as const, initState: { userName: 'Marco' } }))Read the status from anywhere
import { pipe } from 'fp-ts/pipeable'
import * as T from 'fp-ts/Task'
import * as C from 'fp-ts/Console'
const program = pipe(
MS.toTask(appStore),
T.map(s => `Hello ${s.userName}`),
T.chainIOK(C.log)
)
program()Mutation -> mutationRunner
ctorMutation
declare const store: Lazy<Store<S>>
declare const id: number
const mutation = () => MS.ctorMutation('mutation' as const, (id: number) => (currentState: S): Observable<S> => of(s))
const mutationR = MS.mutationRunner(store, mutation)
mutationR(id)mutation with deps
import * as R from 'fp-ts/Reader'
declare const store: Lazy<Store<S>>
declare const id: number
declare const deps: {
someService: someService
}
const mutation = R.asks((deps: typeof deps) =>
MS.ctorMutation('mutation' as const, (id: number) => (currentState: S): Observable<S> => of(s))
)
const mutationR = MS.mutationRunner(store, mutation, { deps: { someService } })
mutationR(id)ctorPartialMutation
mutation runs only if the state matches the predicate, useful if your store is a state machine
declare const store: Lazy<Store<S>>
declare const id: number
const mutation = () =>
MS.ctorPartialMutation(
'partialMutation' as const,
(currentState: S): currentState is SS => currentState.type === 'ss',
(id: number) => (currentState: SS): Observable<S> => of(s)
)
const mutationR = MS.mutationRunner(store, mutation)
mutationR(id)if you want to kill the mutation MS.mutationRunner accept as third parameter "options" with propriety notifierTakeUntil?: Observable<unknown>
Store notifier
emit: initStore, mutationLoad, mutationStart, mutationEnd
declare const store: Lazy<Store<S>>
store().notifier$.subscribe(e =>
Sentry.addBreadcrumb({
category: 'mutation',
message: action.type,
level: Severity.Info,
data: e,
})
)Data fetching
import * as MH from 'mutoid/http'
ajaxToResource
import * as t from 'io-ts'
import { AjaxCreationMethod } from 'rxjs/ajax'
import * as R from 'fp-ts/Reader'
export const somethingDecoders = {
200: t.array(t.string).decode,
400: t.string.decode,
}
type somethingResource = MH.Resource<typeof somethingDecoders>
const fetchSomething = R.asks((deps: { ajax: AjaxCreationMethod }) => (id: number, from: string) =>
MH.ajaxToResource(deps.ajax(`https://api.io?id=${id}&from=${from}`), somethingDecoders)
)resourceFetcherToMutationEffect
import { map } from 'rxjs/operators'
const fetchSomethingMutation = () =>
MS.ctorMutation(
'fetchSomethingMutation' as const,
MH.resourceFetcherToMutationEffect(fetchSomething, (o, s: state) => o.pipe(map(c => ({ ...s, something: c }))))
)if fetchSomething has dependencies, you can do something like this
import { map } from 'rxjs/operators'
import { pipe } from 'fp-ts/function'
import * as R from 'fp-ts/Reader'
export const fetchSomethingMutation = pipe(
fetchSomething,
R.map(fetch =>
MS.ctorMutation(
'fetchSomethingMutation' as const,
MH.resourceFetcherToMutationEffect(fetch, (o, s: state) => o.pipe(map(c => ({ ...s, something: c }))))
)
)
)Rxjs
Operatos
import * as MRX from 'mutoid/rsjx'
chainFirstIO
Perform a side effect and ignore the result
const o = of(1).pipe(MRX.chainFirstIO((uno: number) => IO.of(uno + 2))) // 1chainIOK
Perform a side effect and keep the result
const o = of(1).pipe(MRX.chainIOK((uno: number) => IO.of(uno + 2))) // 3runIO
const o = of(IO.of(1)).pipe(MRX.runIO())extractE
Squash left and right
type e = E.either<L, R>
type result = L | RConstructors
fromIO
const i = IO.of(1)
const o = MRX.fromIO(i).pipe(...)React hooks
useSelector
const userName = useSelector(store, s => s.userName)useMutation
const mutationR = useMutation(store, mutation)useResourceFetcher
import { ajax } from 'rxjs/ajax'
import * as MH from 'mutoid/http'
const somethingFetcher = () => MH.ajaxToResource(ajax('https://api.io'), decoders)
const [resource, dispatch] = useResourceFetcher(fetchSomething, iniState)Run example
yarn dev-serverTest
Unit, lint and cs
yarn testType level
yarn test-type