Effector-react
React bindings for effector
Installation
npm install --save effector effector-react
Or using yarn
yarn add effector effector-react
Usage

import {createStore, createStoreObject, createEvent} from 'effector'
import {createStoreConsumer} from 'effector-react'
const inputText = createEvent('input text')
const text = createStore('').on(inputText, (state, payload) => payload)
const length = createStore(0).on(inputText, (state, payload) => payload.length)
const store = createStoreObject({
text,
length,
})
const FormStore = createStoreConsumer(store)
const Form = () => (
<FormStore>
{state => (
<form>
<input
type="text"
onChange={e => inputText(e.currentTarget.value)}
value={state.text}
/>
<p>Length: {state.length}</p>
</form>
)}
</FormStore>
)
effector 0.18.7-0.18.8
- Add support for passing multiply items at once in
store.reset
import {createStore, createEvent} from 'effector'
const firstTrigger = createEvent()
const secondTrigger = createEvent()
const $target = createStore(0).reset(firstTrigger, secondTrigger)
import React from 'react'
import {createEffect} from 'effector'
import {createComponent} from 'effector-react'
const fetchApiFx = createEffect({
handler: n => new Promise(resolve => setTimeout(resolve, n)),
})
fetchApiFx.pending.watch(console.log)
const Loading = createComponent(
fetchApiFx.pending,
(props, pending) => pending && <div>Loading...</div>,
)
fetchApi(5000)
it's a shorthand for common use case
import {createEffect, createStore} from 'effector'
const fetchApiFx = createEffect()
//now you can use fetchApiFx.pending instead
const $isLoading = createStore(false)
.on(fetchApiFx, () => true)
.on(fetchApiFx.done, () => false)
.on(fetchApiFx.fail, () => false)
Try it
- Introduce
sample
. Sample allows to integrate rapidly changed values with common ui states
import React from 'react'
import {createStore, createEvent, sample} from 'effector'
import {createComponent} from 'effector-react'
const tickEvent = createEvent()
const $tick = createStore(0).on(tickEvent, n => n + 1)
setInterval(tickEvent, 1000 / 60)
const mouseClick = createEvent()
const $clicks = createStore(0).on(mouseClick, n => n + 1)
const sampled = sample($tick, $clicks, (tick, clicks) => ({
tick,
clicks,
}))
const Monitor = createComponent(sampled, (props, {tick, clicks}) => (
<p>
<b>tick: </b>
{tick}
<br />
<b>clicks: </b>
{clicks}
</p>
))
const App = () => (
<div>
<Monitor />
<button onClick={mouseClick}>click to update</button>
</div>
)
see sample in action here
Sampling (signal processing)
- Add babel plugin for automatic naming of events, effects and stores (useful for identifying resources with SSR)
- Add babel plugin for automatic displayName for react components
import React from 'react'
import {createStore, createEvent} from 'effector'
import {createComponent} from 'effector-react'
const $title = createStore('welcome')
console.log('store.shortName', $title.shortName)
// store.shortName title
const clickTitle = createEvent()
console.log('event.shortName', clickTitle.shortName)
// store.shortName clickTitle
const Title = createComponent({title: $title}, (props, title) => (
<h1>{title}</h1>
))
console.log('Component.displayName', Title.displayName)
// Component.displayName Title
Plugins are available out from a box
.babelrc
:
{
"plugins": ["effector/babel-plugin", "effector/babel-plugin-react"]
}
see plugins in action
- Add support for passing events and effects to watchers
import {createStore, createEvent} from 'effector'
const updates = createEvent()
const $state = createStore(0)
$state.watch(updates)
- Improve execution order for sync effects
- Improve typescript typings for createApi (#102)