Skip to main content

Upgrade to version 0.4

New peer dependency

Now fp-ts-rxjs is a peer dependency

State management

We removed the memoization in store ctor.

Now we recommend to use a lazy store like the following one:

const appStore = () => MS.ctor({ name: 'appStore', initState: { userName: 'Marco' } })

In any case you can still use a singleton store. The only difference is the ctor first argument:

// before
const appStore = MS.ctor(() => { name: 'appStore', initState: { userName: 'Marco' } })

// after
const appStore = MS.ctor({ name: 'appStore', initState: { userName: 'Marco' } })

And now when the store is built, it is no more lazy so you have to change some uses, for example

// before
store().state$.pipe(take(1), map(s => ...))

// after
store.state$.pipe(take(1), map(s => ...))

We added mutoid/state/stores to populate the stores and mutations names, using the module augmentation feature:

declare module 'mutoid/state/stores' {
interface Stores {
appStore: 'mutation' | 'partialMutation'
}
}

const appStore = MS.ctor(() => ({
name: 'appStore', // you can remove as const
// nothing changed ...
}))

const mutation = MS.ctorMutation(
'mutation' // you can remove as const
// nothing changed ...
)

This is useful to have the correct inference in the store notifier. In any case, if you don't declare anything there is a fallback to string.

Data fetching

The HTTP module has been splitted into 3 modules: ReaderObservableResource, ObservableResource and Resource. Three data structures that implement an instance of Functor, Apply, Bifunctor, Applicative, Monad (and MonadObservable for ObservableResource and ReaderObservableResource).

Extract resource type form decoders

Before:

import * as t from 'io-ts'
import * as MH from 'mutoid/http'

export const somethingDecoders = {
200: t.array(t.string).decode,
400: t.string.decode,
}

type somethingResource = MH.Resource<typeof somethingDecoders>

After:

import * as t from 'io-ts'
import * as RES from 'mutoid/http/Resource'

export const somethingDecoders = {
200: t.array(t.string).decode,
400: t.string.decode,
}

type somethingResource = RES.ResourceTypeOf<typeof somethingDecoders>

Create Observable resource from ajax

Before:

import * as t from 'io-ts'
import { ajax } from 'rxjs/ajax'
import * as MH from 'mutoid/http'

export const somethingDecoders = {
200: t.array(t.string).decode,
400: t.string.decode,
}

type somethingResource = MH.Resource<typeof somethingDecoders>

const fetchSomething = (id: number, from: string) =>
MH.ajaxToResource(ajax(`https://api.io?id=${id}&from=${from}`), somethingDecoders)

After:

import * as t from 'io-ts'
import { ajax } from 'rxjs/ajax'
import * as ROR from 'mutoid/http/ReaderObservableResource'
import * as OR from 'mutoid/http/ObservableResource'
import * as RES from 'mutoid/http/Resource'

export const somethingDecoders = {
200: t.array(t.string).decode,
400: t.string.decode,
}

export interface Deps {
ajax: typeof ajax
}

type somethingResource = RES.ResourceTypeOf<typeof somethingDecoders>

const fetchSomething = (id: number, from: string) => (deps: Deps) =>
OR.fromAjax(deps.ajax(`https://api.io?id=${id}&from=${from}`), somethingDecoders)

// or

export const fetchSomething = (id: number, from: string) =>
pipe(
ROR.askTypeOf<Deps, typeof somethingDecoders>(),
ROR.chainW(deps =>
ROR.fromAjax(
deps.ajax(`https://ron-swanson-quotes.herokuapp.com/v2/quotes?id=${id}&from=${from}`),
somethingDecoders
)
)
)

Fetcher to mutation effect

Before:

import { map } from 'rxjs/operators'
import * as MH from 'mutoid/http'
import * as MS from 'mutoid/state'

const fetchSomethingMutation = () =>
MS.ctorMutation(
'fetchSomethingMutation' as const,
MH.resourceFetcherToMutationEffect(fetchSomething, (o, s: state) => o.pipe(map(c => ({ ...s, something: c }))))
)

After:

import * as OR from 'mutoid/http/ObservableResource'
import * as ROR from 'mutoid/http/ReaderObservableResource'
import { pipe } from 'fp-ts/function'

// if fetchSomething = (params) => ObservableResource
// return () => Mutation

const fetchSomethingMutation = () =>
pipe(
fetchSomething,
OR.fetchToMutationEffect((s: state) => c => ({ ...s, something: c })),
MS.ctorMutationC('fetchSomethingMutation')
)

// if fetchSomething = (params) => ReaderObservableResource
// return (deps) => Mutation

const fetchSomethingMutation = () =>
pipe(
fetchSomething,
ROR.fetchToMutationEffectR((s: state) => c => ({ ...s, something: c })),
MS.ctorMutationCR('fetchSomethingMutation')
)

Resource fold

Before:

import * as MH from 'mutoid/http'
import { pipe } from 'fp-ts/function'

const result = pipe(
userResource,
MH.resourceFold({
onInit: () => 'loading...',
onSubmitted: () => 'loading...',
onDone: r => r.payload.name,
onFail: e => e.error.type,
})
)

After:

import * as RES from 'mutoid/http/Resource'
import { pipe } from 'fp-ts/function'

const result = pipe(
userResource,
RES.matchD({
onInit: () => 'loading...',
onSubmitted: () => 'loading...',
onDone: r => r.payload.name,
onFail: e => e.error.type,
})
)

// or

const result = pipe(
userResource,
RES.matchD({
onPending: () => 'loading...',
onDone: r => r.payload.name,
onFail: e => e.type,
})
)

// or

const result = pipe(userResource, RES.match(onInit, onSubmitted, onDone, onFail))

The ResourceDone internal structure has been changed.

Before:

export interface ResourceDone<S, P> {
readonly tag: 'done'
readonly status: S
readonly payload: P
}

After:

export interface ResourceData<S, P> {
readonly status: S
readonly payload: P
}

export interface ResourceDone<D> {
readonly _tag: 'done'
readonly data: D
}

The discriminator now is _tag.