Changelog
See also separate changelogs for each library
effector 23.3.0
- Improve error messages: now errors for
skipVoid
and store without sid
will point to the line of store creation. This will help locate troublesome units easily
- Add support for multiple arguments to
scopeBind
. This feature indirectly allows to use multiple arguments in reflect
(issue reflect#91)
- Fix issues with
clearNode
(issue #1200)
effector-vue 23.1.1
- Fix
Date
suppport in useVModel
, createGate
and options API (PR #1228, thanks egoson)
effector-react 23.3.0
effector-vue 23.1.0
- Update useVModel bindings (issue #1150)
- Add support for options api for vue 3 (useful for large codebase migration from vue 2) (issue #1178)
Big thanks to egoson for making this release possible
effector 23.2.3
- Fix types for
attach({ effect })
, allowing to pass explicit name
in this overload (issue #1000)
effector 23.2.2
- Fix types for createEffect and attach in factories with generics (issue #1069). Cases like this now works correctly:
function createModel<T>() {
const $data = createStore<T | null>(null)
const fx = createEffect(() => null as T)
sample({clock: fx.doneData, target: $data})
}
effector-react 23.2.1
- Fix types for
useUnit([fx])
with effect with custom error (PR #1070)
effector 23.2.1
effector-react 23.2.0
- Make
Gate.open
and Gate.close
EventCallable
to allow users to call it in tests
effector 23.2.0
- Improve type validation for derived stores in fork
- Add missed runtime validation for
allSettled
calls with derived units. This case was labeled as a type error, but was forgotten in runtime.
effector 23.1.0
- Support arbitary callbacks in scopeBind. Allows library developers to create better APIs in a way that is Fork API - compatible. PR #1016
- Remove deprecated types for already removed
$store.map
overload. PR #1029
effector-react 23.1.0
- Skip enumerable prototype-inherited properties in
useUnit(shape)
. Some badly-written polyfills might add such properties to built-ins like Array
. PR #1023
- Add missing depreaction tag to the one of
useEvent
overloads. PR #1030
- Add
useProvidedScope
low level API for library developers. PR #1033
effector-react 23.0.1
- Fix warning about
useStore
appeared in useList
(PR #1022)
effector 23.0.0 Spacewatch
Improvements
- Introduce
EventCallable
, StoreWritable
and UnitTargetable
types to allow users to express and understand what could be updated or called directly and what could not. Now createStore
returns StoreWritable
which can be passed to sample target and combine
returns Store
which will show type and runtime error (PR #966)
- Improve error messages: now it includes unit names and locations so it will be useful to find errors in raw server logs or bundles with disabled source maps. To enable locations in errors use
addLoc: true
in babel-plugin. Usually the one wanted to enable this in development only so addLoc
plugin option is disabled by default (PR #1015)
- Add
batch
option to createWatch
(PR #850)
- Add
@withease/factories
to babel-plugin defaults (PR #995)
- Add all
patronum
modules to babel-plugin defaults (PR #996)
- Rename
greedy
to batch
in sample
. greedy: true
becomes batch: false
which is a better mental model for what this option do (PR #972)
- Unify programmatic sid insertion in
merge
and restore
(PR #969)
- Allow
domain
to be used in attach
without parent effect (PR #895)
Bug fixes
- Fix nullable type of
.reinit
, now it exists in StoreWritable
and not exists in Store
(PR #966)
- Fix serialization of ignored stores (PR #903)
- Fix race condition in parallel effect calls (PR #849)
- Fix scope reading its initial values from current (not initial) store value (PR #909)
- Fix duplicated
combine
calls (PR #916)
- Fix reading stale value in
attach
(PR #1011)
Deprecations and removed apis
- Deprecate undefined as magical value to skip store updates, use
skipVoid: true
option in combine
and map
to enable old behavior. Getting rid of that edge case will allow to introduce lazy computations (issue #920)
- Deprecate
forward
and guard
in favor of sample
(PR #913)
- Deprecate
reactSsr
option in babel-plugin (PR #910)
- Deprecate
onlyChanges
option in serialize
(PR #907)
- Deprecate raw object
{[fx.sid]: Function}
in fork handlers
(PR #973)
- Deprecate
.watch
with second argument in favor of sample
(PR #906)
- Deprecate
.getType()
- relic from ancient times which exists for redux compatibility (PR #899)
- Deprecate
effector/babel-plugin-react
(PR #948)
- Deprecate
fork(domain)
and hydrate(domain)
- this api existed for traking units in scopes when Fork API was introduced, but starting from 22 version this is done automatically and domain is no longer required for that (PR #950)
- Throw error when unit called from a pure function (PR #905)
- Throw error when derived event is called (PR #905)
- Throw error when
fn
in $store.map(fn)
returns undefined
in the initialization (issue #828)
- Remove flow typings. In the beginning, the effector was written in flow, but now only types remained and they were extremely outdated due to lack of expertise in the technology. The flow community maintains bindings in a separate repository. (PR #912)
- Remove deprecated
effector/fork
module (PR #842)
- Remove deprecated
createStoreObject
alias for combine
(PR #908)
- Remove deprecated
.thru
method (PR #843)
- Remove deprecated second argument with state from
$store.map
(PR #846)
- Remove deprecated
restore($store)
support. This was an obscure feature when store is passed to method and returned without changes as is (PR #1018)
effector-react 23.0.0
- Deprecate
effector-react/scope
in favor of isomorphic hooks (PR #979)
- Deprecate
useStore
, useEvent
, connect
and createStoreConsumer
in favor of universal useUnit
(PR #951)
- Deprecate
createComponent
in favor of @effector/reflect
- Remove deprecated
effector-react/ssr
module (PR #844)
- Remove deprecated createReactState and createContextComponent (PR #845)
effector-solid 0.23.0
- Make all hooks isomorphic
- Deprecate
effector-solid/scope
in favor of isomorphic hooks (PR #979)
effector-vue 23.0.0
- Add
useUnit
hook (PR #1003)
- Make bindings isomorphic
- Deprecate
effector-vue/ssr
in favor of isomorphic hooks (PR #1005)
- Remove obsolete deprecated apis
$watchAsStore
and $store
(PR #1004)
effector 22.8.8
- Add new types from effector 23:
UnitTargetable
, EventCallable
and StoreWritable
as aliases to improve migration experience and ecosystem compatibility
effector 22.8.7
- Fix
combine
function called twice on first allSettled
call (PR #984)
effector-react 22.5.4
- Fix for
createWatch
implementation to improve @effector/next
updates flow
effector-react 22.5.3
- Fix too frequent
useUnit
updates
effector 22.8.6
- Follow-up fix for
22.8.2
: now combine
in tuple-form handles compelx edge-cases with mapped stores correctly. (PR #902)
effector-react 22.5.2
effector 22.8.5
- Follow up fix for
22.8.4
: now fix works for fork({ handlers })
calls too. PR #898
effector 22.8.4
- Fixed an edge case for
fork
calls without sid (function from release 22.8.0
). Some libraries provide built-in sid's in the code, which led to the duplicated sid found
exception when calling fork
when trying to use two instances of the same factory in a test and running it without effector/babel-plugin
.
The exception on fork
calls is no longer thrown, and all sid-related checks and assertions have been moved to serialize
calls, since sid's are actually only required for serialize
to work. PR #897
effector 22.8.3
- Added missing node and stateRef ids to meta-objects. These are internal changes which are not covered by the types or docs yet.
effector 22.8.2
combine
types now allow primitive values, just like it was stated in the docs. Thanks to @faustienf PR #884
- Events, created from split with match-object shape and internal inFlight counters of Effects now have proper metadata to use in the Inspect API. PR #892
effector 22.8.1
- Internal state refs now also see meta, if owned by store. PR #889
effector 22.8.0
- Sids are no longer required for
fork({ values, handlers })
, which allows to run tests without effector/babel-plugin
. Note, that plugin and sids are still required for SSR. (PR #855)
effector-react 22.5.1
- Fix Gate usage as component.
<Gate />
will also be isomorphic by scope.
effector 22.7.0
- Fix
Declaration
type, provide missing top-level properties for region
and factory
types
- Add node's
id
to Declaration
type
effector 22.6.2
- Fix return type of
withRegion
effector 22.6.1
- Add missing
exports
definition for effector/inspect
API
effector 22.6.0
effector 22.5.2
- Fix
serialize: "ignore"
in fork({ values })
(PR #862)
effector 22.5.1
- Fix default factories list in babel-plugin (PR #857)
effector-react 22.5.0
- Make
useGate
isomorphic in effector-react
module, so the one not needed to use effector-react/scope
anymore (PR #852)
- Fix
useUnit
hangs when scope is changed (happens when route is changed in next.js) (PR #851)
effector 22.5.0
effector-react 22.4.0
effector-solid 0.22.7
effector 22.4.1
- Add type support for read only arrays in sample
source
. This case now supported and typechecked correctly:
const profileFormSubmitted = createEvent()
const $name = createStore('alice')
const $age = createStore(0)
const saveProfileFx = createEffect(async ([name, age]: [string, number]) => {})
sample({
clock: profileFormSubmitted,
source: [$name, $age] as const,
target: saveProfileFx,
})
Note that the one need to use "as const" in that case to got correct typechecking because without it typescript cannot infer the type [Store<string>, Store<number>]
. We are working to avoid that limitation, stay tuned!
effector Encke 22.4.0
- Add custom serializers for Store (PR #744)
- Allow to pass domain as an argument for createEvent and similar methods (PR #763)
- Add
store.reinit
event to set default value into store (PR #797)
const $store = createStore<Array<number>>([])
sample({
clock: someEffectFailed,
target: $store.reinit,
})
sample({
clock: $store.reinit,
fn: createEffect(() => console.log('store value set to default')),
})
- Add safe mode for scopeBind (PR #688)
- Add
is.attached
method to detect effects created via attach
(PR #670)
- Add @farfetched/core and atomic-router to default factories so the one not needed to describe them explicitly
- Protect against combine argument being broken via Array.slice (PR #801)
- Add "type" entry for package exports (PR #759)
- Finally allow
Gate
to be serialized (as this requires changes in babel plugin) (PR #683)
effector-react 22.3.4
- Fix useUnit skipping updates when used with useEffect and useGate
effector-react 22.3.3
- Fix useUnit skipping updates during scope changes (often happens in next.js apps). Big thanks to @AlexandrHoroshih for investigation
effector-react 22.3.1
- Fix useUnit skipping updates in react 16-17
effector-vue 22.2.0
effector-react 22.3.0
- Made hooks
useEvent
, useStore
, useStoreMap
and useList
isomorphic, now they would use scope
from the Provider
if it is available and scope-less mode otherwise. For useUnit
it was done in 22.2.0.
- Added parameter
forceScope
to useEvent
, useStore
, useStoreMap
and useList
to force usage of scope from Provider
, it would throw an error if Provider
is not available, /scope
module sets forceScope
to true
by default
effector-solid 0.22.6
- Add type of
Provider
to main module
effector-solid 0.22.5
- Add export of
Provider
from main module
effector-react 22.2.0
- Made hook
useUnit
isomorphic, now it would use scope
from the Provider
if it is available and scope-less mode otherwise (PR #776 and PR #785)
- Added parameter
forceScope
to useUnit
to force usage of scope from Provider
, it would throw an error if Provider
is not available (PR #776 and PR #785), /scope
module sets forceScope
to true
by default
- Added "type" entry for package exports (PR #759)
- Fixed typing in
useUnit
(PR #747)
effector-solid 0.22.4
- Made
useUnit
isomorphic, now it would use scope
from the Provider
if it is available and scope-less mode otherwise (PR #782)
- Added parameter
forceScope
to useUnit
to force usage of scope from Provider
, it would throw an error if Provider
is not available (PR #782), /scope
module sets forceScope
to true
by default
effector-vue 22.1.2
- Added "type" entry for package exports (PR #759)
effector-solid 0.22.3
- Added "type" entry for package exports (PR #759)
effector-solid 0.22.2
- Fixed typing in
useUnit
(PR #747)
forest 0.21.2
- Added "type" entry for package exports (PR #759)
effector-react 22.1.0
- Added support for react 18 (PR #655)
- Added
useUnit
method to read multiple stores and bind events or effects to scope in a single batched call (PR #733, #738)
import {value createEvent, value createStore, value fork} from 'effector'
import {value useUnit, value Provider} from 'effector-react/scope'
const inc = createEvent()
const $count = createStore(0)
const $title = createStore('useStore example')
$count.on(inc, x => x + 1)
const App = () => {
const [count, title, incFn] = useUnit([$count, $title, inc])
return (
<>
<h1>{title}</h1>
<p>Count: {count}</p>
<button onClick={() => incFn()}>increment</button>
</>
)
}
const scope = fork()
render(
() => (
<Provider value={scope}>
<App />
</Provider>
),
document.getElementById('root'),
)
- Added
placeholder
option to useList
to render in cases of empty list
const ChatList = () => (
<div>
{useList($chats, {
fn: chat => <div>Chat {chat.name}</div>,
keys: [],
placeholder: <div>You have no chats yet. Add first one?</div>,
})}
</div>
)
- Added
defaultValue
option to useStoreMap
to return in cases when fn
returns undefined
const ChatName = ({id}) => {
const chat = useStoreMap({
store: $chats,
keys: [id],
fn: chats => chats.find(chat => chat.id === id),
defaultValue: {id: 'default', name: 'Default chat'},
})
return <span>{chat.name}</span>
}
- Fixed
Gate.status
store being serialized (PR #683)
effector 22.2.0
- Added
filter
option to sample
, thereby making guard
an alias (issue #521)
sample({
clock: submitPasswordEvent,
source: $store,
filter: (state: AuthFlowState) => state is WaitingPasswordState,
fn: (waitingPasswordState, clock) => waitingPasswordState.password,
target: submitPassowrdFx,
})
- Added
clock
option to split
(issue #537)
split({
clock: submit,
source: $form,
match: $mode,
cases: {
draft: saveFormDraftFx,
send: sendFormToBackendFx,
},
})
- Improved
sample
type checking:
- Fixed cases when target units becomes compatible with any type (issue #600)
- Fixed cases when method call being marked as error when it perfectly correct
- Removed vague "incompatible unit in target" error
- Error messages now explicitly tells which type is given by source and which one is expected by target
- 16 overloads was merged into single one to improve clarity of error messages. Will remove a lot of noise from IDE output thereby improving developer expirience
- Improved
split
type checking:
- Fixed a case when units in cases becomes compatible with any type
- Removed vague "incompatible unit in target" error
- Error messages now explicitly tells which type is given by source and which one is expected by failed target case
- Added jsdoc documentation for all top level methods. Will be used by IDE such as VS Code and Webstorm to provide better developer expirience
- Derived units in target of
sample
, guard
, split
and forward
are deprecated (issue #563)
- Imperative calls of derived units created by
merge
, sample
and split
are deprecated
- Imperative calls of events and effects in pure functions are deprecated (issue #541)
restore($store)
is deprecated (issue #571)
- Effects created by
attach
got correct name for use in developer tools like effector-logger (issue #527)
- Fixed a case when
sample/guard
pass obsolete data from it's source
store (issue #544)
- Fixed data race when using
combine
with fork api (issue #613)
- Fixed cases when
effector/babel-plugin
changes function calls which it should avoid (issue #603)
- Fixed support for multiple passes of
effector/babel-plugin
(issue #601)
- Fixed
combine
support for units with large union types (issue #531)
- Fixed support for calls without payload for
Event<unknown>
(PR #454)
- Fixed circular reference warning during import of typings (issue #578)
effector-vue 22.1.0
effector-react 22.0.6
- Fix
Can't perform a React state update on an unmounted component
warning for useStoreMap
in a few cases (issue #574)
effector 22.1.2
- Allow to use
effector/babel-plugin
in patronum/macro
effector 22.1.1
- Fix data races that cause obsolete states to appear in the
.on
and .reset
methods
effector 22.1.0
- Added option
debugSids
to effector/babel-plugin
The option allows adding file path and variable name to a sid for each unit definition.
It allows to easily debug serialized scope using SSR.
effector 22.0.0
- Add support for plain functions to attach:
attach({source, async effect(source, params) {}})
- Allow to use fork without domains:
const scope = fork()
Unit not found in scope
error is no longer exists, any unit could be used in any scope
- Increase performance of
fork
and serialize
a hundredfold
- Add support for attached effects to fork handlers
- Add support for tuples to fork values and handlers:
fork({values: [[$user, 'alice'], [$age, 22]]})
- Add
serialize: 'ignore'
option to createStore
to declare store as ignored by serialize
calls
- Make
onlyChanges: true
a default serialize
option
- Fix babel plugin issue with parsing method calls (e.g. in react native)
- Validate
combine
arguments and throw an error in case of undefined
and non-store units (issue #509)
- Throw an error when fork handlers or values got units without sid or with duplicate sid
- Deprecate
createStoreObject
alias for combine
- Deprecate
effector/fork
module
- Deprecate
.thru
- Deprecate second argument in
store.map
- Deprecate direct manipulations with derived units:
- Deprecate
.on
in derived stores created by store.map
and combine
- Deprecate calls of derived events created by
event.map
, event.filterMap
and event.filter
- Deprecate calls of
fx.done
, fx.doneData
and other events belongs to effects
- Remove
ɔ
(latin small letter open o) symbol to prevent incorrect unicode parsing
- Remove undocumented
scope.find
which is a wrong abstraction for a new fork
- Make
Scope
a unit:
- Add support for
Scope
to is.unit
- Add
is.scope
method
- Allow to pass a scope to scopeBind:
scopeBind(unit, {scope})
, which is also can be used outside from .watch
- Improve es modules support
- Make package size 10% smaller
effector-react 22.0.0
- Add module
effector-react/scope
and make effector-react/ssr
an alias for it
- Fix
Cannot update a component
warning in useGate
- Allow to return
undefined
in useStoreMap
- Make
domain
field in createGate
optional
- Deprecate
createContextComponent
and createReactState
- Improve es modules support
effector-vue 22.0.0
- Improve es modules support
forest 0.20.0
- Improve es modules support
effector-react 21.3.1
- Fixed TypeError in
useStoreMap
with scope (PR #474)
effector-react 21.3.0
- Add support for
updateFilter
to useStoreMap
. It helps to control component rerendering, e.g. when component should rerender only when id
field is changed
- Add
useStoreMap($store, value => result)
shorthand
- Add support for
getKey
to useList
. Function in this field will be used to compute key for every item of list
- Add support for stores with functions in them to
useStore
(PR #431)
- Add domain name passed to
createGate
to gate.displayName
and gate units (issue #449)
- Fix unhandled promise rejection in
useEvent
when used effect throw an error
effector 21.8.0
- Add type support for arrays in
sample
target
(PR #284, #445)
sample({
clock: clickValidate,
source: $formFields,
target: [validateForm, sendStatsFx],
})
- Add support for case functions, case stores and matcher stores to
split
. Case functions and stores will choose target case by its name, matcher stores are boolean stores which indicate whether to choose given case
const source = createEvent()
const even = createEvent()
const $odd = createStore(0)
split({
source,
match(n) {
if (n % 2 === 0) return 'even'
return 'odd'
},
cases: {
even,
odd: $odd,
},
})
const $currentPage = createStore('dashboard')
split({
source,
match: $currentPage,
cases: {
dashboard: even,
__: odd,
},
})
const tryUpdatePage = createEvent()
const updatePageFx = createEffect()
const $hasWriteAccess = createStore(false)
split({
source: tryUpdatePage,
match: {
admin: $hasWriteAccess,
},
cases: {
admin: updatePageFx,
},
})
- Add
updateFilter
config field to createStore
to skip arbitrary store updates (discussion #428)
const $playerPosition = createStore(
{x: 0, y: 0},
{
updateFilter: (update, current) => update.x !== current.x,
},
)
- Add support for
sample
with clock
without source
. For example, it useful in cases when clock
is array of units and no source
stores is needed
sample({
clock: [fx1.doneData, fx2.doneData],
fn: data => ({url: '/stats', data})
target: fetchFx,
})
- Add support for
clock
to guard
to improve developer expirience in cases when update trigger (clock
field) and data source (source
field) are different things
guard({
clock: validateForm,
source: $formFields,
filter: formFields => validator(formFields),
target: submitFormFx,
})
Add addNames
field to babel plugin (PR #450)
Add type support for Scope
to clearNode
(issue #441)
Add compositeName
to Domain
typings, making it consistent with other units
Add EventPayload
and UnitValue
type helpers (PR #434)
Improve various edge cases with fork api and serialization
Improve typechecking for attach
(issue #439)
Fix various type issues in sample
and guard
typings
effector-react 21.2.0
- Add
createGate
implementation to effector-react/ssr
import {createDomain} from 'effector'
import {createGate, useGate} from 'effector-react/ssr'
const app = createDomain()
const currentRouteGate = createGate({
domain: app,
defaultState: 'dashboard',
})
export const Layout = ({routeName, children}) => {
useGate(currentRouteGate, routeName)
return (
<>
<h1>{routeName}</h1>
{children}
</>
)
}
effector-react 21.1.0
- Add support for object and array of events to
useEvent
. It's a shorthand for calling several useEvent
at once (PR #425 by @sergeysova)
export function ExampleComponent() {
const handlers = useEvent({emailChanged, passwordChanged})
return (
<div>
<input onChange={handlers.emailChanged} />
<input onChange={handlers.passwordChanged} />
</div>
)
}
export function ExampleComponent() {
const [changeEmail, changePassword] = useEvent([
emailChanged,
passwordChanged,
])
return (
<div>
<input onChange={changeEmail} />
<input onChange={changePassword} />
</div>
)
}
effector 21.7.0
Add support for scopes to hydrate
, to provide a way to fill additional values to existing scope (happens during SSG navigation in next.js)
Improve prepend
type inference (PR #415 (thanks @doasync))
effector-vue 21.1.0
- Add support for vue@next (vue 3)
useStore
useVModel
useGate
createGate
see docs
effector 21.6.0
- Add support for user-defined factories in fork api. Starting from this release, application developers can use their own functions and be sure that their content will be properly serialized and hydrated by fork api.
New field
factories
in effector/babel-plugin
accepts array of module names which exports will be treated as custom factories therefore each function call will provide unique prefix for sid
properties of units inside them
`
json title=".babelrc"
{
"plugins": [
[
"effector/babel-plugin",
{
"factories": ["src/createEffectStatus", "~/createCommonPending"]
}
]
]
}
```js title="./src/createEffectStatus.js"
import {rootDomain} from './rootDomain'
export function createEffectStatus(fx) {
const $status = rootDomain
.createStore('init')
.on(fx.finally, (_, {status}) => status)
return $status
}
`
js title="./src/statuses.js"
import {createEffectStatus} from './createEffectStatus'
import {fetchUserFx, fetchFriendsFx} from './api'
export const $fetchUserStatus = createEffectStatus(fetchUserFx)
export const $fetchFriendsStatus = createEffectStatus(fetchFriendsFx)
Import `createEffectStatus` from `'./createEffectStatus'` was treated as factory function so each store created by it has its own `sid` and will be handled by serialize independently, although without `factories` they will share the same `sid`
[factories in documentation](https://effector.dev/docs/api/effector/babel-plugin#factories)
- Add user-friendly unit name in fork api error messages when given unit is not found in scope. This improves error messages in both `effector` and `effector-react`
- Add validation for `values` and `handlers` fields in `fork` and for `values` field in `hydrate`
- Add type support for `createEffect<typeof handler, Error>(handler)` to infer `Params` and `Done` types from given `handler` and provide custom `Fail` type at the same time
[createEffect and custom errors](https://effector.dev/docs/typescript/typing-effector#createeffect-and-custom-errors) in documentation
- Improve `guard` return type inference (PR [#406](https://github.com/effector/effector/pull/406) (thanks [@doasync](https://github.com/doasync)))
- Fix void params support for `createEffect(name, config)` (issue [#404](https://github.com/effector/effector/issues/404))
- Allow to use `Event<void>` in cases when only `() => void` is accepted (PR [#400](https://github.com/effector/effector/pull/400) (thanks [@doasync](https://github.com/doasync)))
- Add support for `merge` to `effector/babel-plugin`
## effector 21.5.0
- Add support for `attach({effect})` to create effect which will call `effect` with params as it is. That allow to create separate effects with shared behavior (PR [#396](https://github.com/effector/effector/pull/396) and [#397](https://github.com/effector/effector/pull/397) (thanks [@sergeysova](https://github.com/sergeysova) and [@oas89](https://github.com/oas89)))
- Add `reactSsr` option to `effector/babel-plugin` to replace imports from `effector-react` to `effector-react/ssr`. Useful for building both server-side and client-side builds from the same codebase
## effector 21.4.0
- Add support for return status to `allSettled`. When `allSettled` is called with `Effect`, it return object with `value` and `status` fields ([discussion](https://github.com/effector/effector/issues/385))
```js
import {createDomain, fork, allSettled} from 'effector'
const app = createDomain()
const fx = app.createEffect(() => 'ok')
const result = await allSettled(fx, {scope: fork(app)})
// => {status: 'done', value: 'ok'}
Try it
- Allow to expicitly define return/error types in
createEffect(handler)
const fx = createEffect<number, string, Error>(x => x.toString())
Add types for domain.effect(handler)
Fix effector/babel-plugin behavior in case when methods like createStore
are imported from unrelated library and should be ignored. Import library could be defined by importName config field
Improve fork api support for watchers
effector 21.3.0
- Add support for
createEffect(handler)
createEffect(handler) in documentation
import {createEffect} from 'effector'
const fetchUserReposFx = createEffect(async ({name}) => {
const url = `https://api.github.com/users/${name}/repos`
const req = await fetch(url)
return req.json()
})
fetchUserReposFx.done.watch(({params, result}) => {
console.log(result)
})
await fetchUserReposFx({name: 'zerobias'})
Try it
- Add support for
attach({source, effect})
without mapParams
: in case with source
and effect
only, inner effect will be triggered with source
values
attach({effect, source}) in documentation
import {createStore, createEffect, attach} from 'effector'
const fx = createEffect()
const $token = createStore('')
const secureRequest = attach({effect: fx, source: $token})
it's a shorthand for common use case:
import {createStore, createEffect, attach} from 'effector'
const fx = createEffect()
const $token = createStore('')
const secureRequest = attach({
effect: fx,
source: $token,
mapParams: (_, source) => source,
})
Try it
- Handle throws in
attach
mapParams
field: errors happened in mapParams
function will force attached effect to fail
- Add babel plugin support for
split
and createApi
- Add
name
field to attach
typings
- Add
.filter
and .filterMap
to effect typings (PR #376)
- Improve config validation for
forward
, attach
, sample
and guard
: attempt to call these methods without arguments will lead to error with user-friendly description
- Improve fork api support for stores and events
effector 21.2.0
- Add array support for sample
clock
field which acts like a merge
call
import {
value createStore,
value createEvent,
value createEffect,
value sample,
value merge,
} from 'effector'
const showNotification = createEvent<string>()
const trigger = createEvent()
const fx = createEffect()
const $store = createStore('')
sample({
source: $store,
clock: [trigger, fx.doneData],
target: showNotification,
})
sample({
source: $store,
clock: merge([trigger, fx.doneData]),
target: showNotification,
})
- Improve ide type hints support for
sample
in case of config form
- Add
package.json
to package exports
field (read more in nodejs documentation)
effector 21.1.0
Add onlyChanges
option to serialize
to ignore stores which didn't changed in fork (prevent default values from being carried over network)
Add type helpers for stores and effects: StoreValue
, EffectParams
, EffectResult
and EffectError
import {
value createStore,
value createEffect,
value StoreValue,
value EffectParams,
value EffectResult,
} from 'effector'
const getUserFX = createEffect<number, {name: string}>()
const $username = createStore('guest')
type Username = StoreValue<typeof $username>
type GetUserParams = EffectParams<typeof getUserFX>
type User = EffectResult<typeof getUserFX>
- Allow
domain.createEffect
to infer type from given handler
(that feature was already implemented for createEffect
method), this code now typechecked as expected:
import {value createDomain} from 'effector'
const app = createDomain()
const voidFx = app.createEffect({
async handler() {},
})
await voidFx()
- Allow to call
allSettled
with void units without params
field, this code now typechecked as expected:
import {value createDomain, value fork, value allSettled} from 'effector'
const app = createDomain()
const voidFx = app.createEffect({
async handler() {},
})
voidFx()
const scope = fork(app)
await allSettled(voidFx, {scope})
effector 21.0.3, effector-react 21.0.4, effector-vue 21.0.3
effector 21.0.0
- Add object form of
split
for pattern-matching without additional forwards
split
in documentation
import {split, createEffect, createEvent} from 'effector'
const messageReceived = createEvent()
const showTextPopup = createEvent()
const playAudio = createEvent()
const reportUnknownMessageTypeFx = createEffect({
handler({type}) {
console.log('unknown message:', type)
},
})
split({
source: messageReceived,
match: {
text: msg => msg.type === 'text',
audio: msg => msg.type === 'audio',
},
cases: {
text: showTextPopup,
audio: playAudio,
__: reportUnknownMessageTypeFx,
},
})
showTextPopup.watch(({value}) => {
console.log('new message:', value)
})
messageReceived({
type: 'text',
value: 'Hello',
})
messageReceived({
type: 'image',
imageUrl: '...',
})
Try it
You can match directly to store api as well:
import {split, createStore, createEvent, createApi} from 'effector'
const messageReceived = createEvent()
const $textContent = createStore([])
split({
source: messageReceived,
match: {
text: msg => msg.type === 'text',
audio: msg => msg.type === 'audio',
},
cases: createApi($textContent, {
text: (list, {value}) => [...list, value],
audio: (list, {duration}) => [...list, `audio ${duration} ms`],
__: list => [...list, 'unknown message'],
}),
})
$textContent.watch(messages => {
console.log(messages)
})
messageReceived({
type: 'text',
value: 'Hello',
})
messageReceived({
type: 'image',
imageUrl: '...',
})
messageReceived({
type: 'audio',
duration: 500,
})
Try it
- Merge
effector/fork
into effector
. Now all methods required for SSR are exported from the library itself, making effector/fork
an alias
- Make
Scope
type alias for Fork
- Add support for es modules:
import {createStore} from 'effector/effector.mjs'
- Effect without a handler now throws an error during a call instead of calling
console.error
with undefined return, which was violating the type of effect
- Remove
restore
aliases, event.filter(fn)
alias for event.filterMap(fn)
, greedy
in sample
as separate last argument and unused blocks
and Kind
effector-react 21.0.0
- Add support for es modules
- Remove experimental
Gate.isOpen
plain property, which was incompatibile with concurrent mode and ssr, use Gate.status
instead
Gate.status in documentation
effector-vue 21.0.0
- Add support for es modules
effector-react 20.9.0
- Export
useGate
with fork
support from effector-react/ssr
import {value useGate, value useStore, value Provider} from 'effector-react/ssr'
import {value createGate} from 'effector-react'
import {value createDomain, value forward} from 'effector'
import {value fork} from 'effector/fork'
const app = createDomain()
const activeChatGate = createGate({domain: app})
const getMessagesFx = app.createEffect({
async handler({chatId}) {
return ['hi bob!', 'Hello, Alice']
},
})
const $messagesAmount = app
.createStore(0)
.on(getMessagesFx.doneData, (_, messages) => messages.length)
forward({
from: activeChatGate.open,
to: getMessagesFx,
})
const ChatPage = ({chatId}) => {
useGate(activeChatGate, {chatId})
return (
<div>
<header>Chat {chatId}</header>
<p>Messages total: {useStore($messagesAmount)}</p>
</div>
)
}
const App = ({root}) => (
<Provider value={root}>
<ChatPage chatId="chat01" />
</Provider>
)
const scope = fork(app)
ReactDOM.render(<App root={scope} />, document.getElementById('root'))
Try it
- Add
domain
optional field to createGate
which will be used to create gate units (useful for ssr)
createGate({domain}) in documentation
- Improve
useList
hook typings for typescript exported from effector-react/ssr
by allowing usage as components' return value (fix DefinitelyTyped issue)
effector 20.17.2
- Add effects created via
attach
to domain effects, allowing these effects to be called within other effects when using fork
import {createDomain, attach} from 'effector'
import {fork, allSettled} from 'effector/fork'
const app = createDomain()
const addFx = app.createEffect({handler: _ => _})
const $count = app.createStore(2).on(addFx.doneData, (x, y) => x + y)
const addWithCurrent = attach({
source: $count,
effect: add,
mapParams: (params, current) => params + current,
})
const startFx = app.createEffect({
async handler(val) {
await addWithCurrent(val)
},
})
const scope = fork(app)
await allSettled(startFx, {
scope,
params: 3,
})
console.log(scope.getState(count))
Try it
- Add validation for
combine
first argument which should be store, object with stores or array with stores PR #362 (thanks @doasync)
effector 20.17.1
- Add validation for
event.watch
watcher, this code now throw error as expected:
import {createEvent} from 'effector'
const trigger = createEvent()
trigger.watch(NaN)
Try it
effector 20.17.0
- Add support for nested effect calls in forked scope. Parallel requests are supported as well
import {createDomain, forward} from 'effector'
import {fork, allSettled} from 'effector/fork'
const app = createDomain()
const addWordFx = app.createEffect({handler: async word => word})
const words = app
.createStore([])
.on(addWordFx.doneData, (list, word) => [...list, word])
const startFx = app.createEffect({
async handler(word) {
await addWordFx(`${word}1`)
await addWordFx(`${word}2`)
return word
},
})
const nextFx = app.createEffect({
async handler(word) {
await Promise.all([addWordFx(`${word}3`), addWordFx(`${word}4`)])
},
})
forward({from: startFx.doneData, to: nextFx})
const scopeA = fork(app)
const scopeB = fork(app)
const scopeC = fork(app)
await Promise.all([
allSettled(startFx, {
scope: scopeA,
params: 'A',
}),
allSettled(startFx, {
scope: scopeB,
params: 'B',
}),
])
await allSettled(startFx, {
scope: scopeC,
params: 'C',
})
console.log(scopeA.getState(words))
console.log(scopeB.getState(words))
console.log(scopeC.getState(words))
Try it
- Allow
createNode
to call without arguments
import {createNode} from 'effector'
const node = createNode()
- Make
Step
type alias for Node
effector-react 20.8.0
- Add ability to define default
Gate
state in createGate
via defaultState
field
createGate({defaultState}) in documentation
- Remove
object
restriction from createGate
Props
type in typescript, as it becomes useless with introduction of useGate
. This code now passes type checking successfully
import {value createGate} from 'effector-react'
const RouteGate = createGate<string>()
const UserGate = createGate({defaultState: 'guest'})
effector 20.16.1
- Allow typescript to refine type if
guard
got Boolean
(a function) as filter
import {value createEvent, value createStore, value guard} from 'effector'
type User = {name: string}
const trigger = createEvent<User | null>()
const user = createStore<User>({name: 'alice'})
guard({
source: trigger,
filter: Boolean,
target: user,
})
effector-react 20.7.4
effector-vue 20.5.0
const fx = createEffect({...});
export default Vue.extend({
effector: {
isCompleted: fx.done
},
watch: {
isCompleted(sid) {
this.isPopupOpened = false;
}
},
data: () => ({
isPopupOpened: true,
})
})
- Support v-model directive for scalar values
const $msg = createStore()
export default Vue.extend({
effector: {
$msg,
},
})
<template>
<input v-model="$msg" />
</template>
effector 20.16.0
- Add support for
handlers
to fork
to change effect handlers for forked scope (useful for testing)
import {value createDomain} from 'effector'
import {
value fork,
value hydrate,
value serialize,
value allSettled,
} from 'effector/fork'
const app = createDomain()
const fetchFriendsFx = app.createEffect<{limit: number}, string[]>({
async handler({limit}) {
return []
},
})
const $user = app.createStore('guest')
const $friends = app
.createStore([])
.on(fetchFriendsFx.doneData, (_, result) => result)
const testScope = fork(app, {
values: {
[$user.sid]: 'alice',
},
handlers: {
[fetchFriendsFx.sid]: () => ['bob', 'carol'],
},
})
await allSettled(fetchFriendsFx, {
scope: testScope,
params: {limit: 10},
})
console.log(testScope.getState(friends))
Try it
- Add support for
scope.getState(store)
to access to store values in forked scopes
- Fix
values
support for fork
effector-react 20.7.3, effector-vue 20.4.2
- Fix regression in
effector-react/compat
and effector-vue/compat
compatibility with IE11
effector-vue 20.4.1
- Improve typescript typings for usage via
Vue.extend
(PR #343)
effector 20.15.1
- Fix additional store updates during state hydration
import {createDomain, forward} from 'effector'
import {hydrate} from 'effector/fork'
const app = createDomain()
const saveUserFx = app.createEffect({
handler(value) {
console.log('saveUserFx now called only after store update', value)
},
})
const $username = app.createStore('guest')
forward({
from: $username,
to: saveUserFx,
})
$username.updates.watch(value => {
console.log('event watches now called only after store update', value)
})
hydrate(app, {
values: {
[$username.sid]: 'alice',
},
})
Try it
effector 20.15.0
- Add support for array of units to
store.on
(PR #328)
import {createEvent, createStore} from 'effector'
const changedA = createEvent()
const changedB = createEvent()
const $store = createStore(0).on(
[changedA, changedB],
(state, params) => state + params,
)
$store.watch(value => {
console.log('updated', value)
})
changedA(2)
changedB(2)
$store.off(changedA)
Try it
Documentation for store.on
- Add support for array of units to
store.reset
to make it consistent with merge and store.on
import {createEvent, createStore} from 'effector'
const increment = createEvent()
const reset = createEvent()
const $store = createStore(0)
.on(increment, state => state + 1)
.reset([reset])
$store.watch(state => console.log('changed', state))
increment()
increment()
reset()
Try it
Documentation for store.reset
- Remove units erased with
clearNode(unit)
from their parent domain hooks and history sets
effector-react 20.7.1
- Improve
useList
hook typings for typescript by allowing usage as components' return value (fix DefinitelyTyped issue)
This code now works without type errors:
import {value createStore} from 'effector'
import {value useList} from 'effector-react'
const $users = createStore<User[]>([
{
username: 'alice',
email: 'alice@example.com',
bio: '. . .',
},
{
username: 'bob',
email: 'bob@example.com',
bio: '~/ - /~',
},
{
username: 'carol',
email: 'carol@example.com',
bio: '- - -',
},
])
const UserList = () => useList($users, ({username}) => <p>{username}</p>)
const App = () => (
<div>
<UserList />
</div>
)
effector 20.14.0
- Add
ignore
parameter to serialize
to skip stores during app state serialization PR #325 (thanks @sergeysova)
effector-react 20.7.0
- Use shallow compare for skipping updates with
useGate
, thereby making it consistent with <Gate />
- Remove nesting from components, created by
createContextComponent
and createReactState
, which previously were based on createComponent
effector 20.13.6
- Fix cases with
effector/babel-plugin
when inability to determine unit name led to the absence of sid
property
effector 20.13.5
- Extend typescript support for any to void forwarding: add support for forwarding to array of void units
import {value forward, value createEvent, value createEffect} from 'effector'
const sourceA = createEvent<string>()
const sourceB = createEvent<number>()
const targetA = createEvent<void>()
const fx = createEffect<void, any>()
forward({
from: sourceA,
to: targetA,
})
forward({
from: sourceA,
to: [targetA, fx],
})
forward({
from: [sourceA, sourceB],
to: targetA,
})
forward({
from: [sourceA, sourceB],
to: [targetA, fx],
})
- Fix computed stores support for
hydrate
- Fix
allSettled
support for effects as first argument
effector 20.13.0
- Introduce
attach
: wrapper for effect, which allow to map effect arguments and use data from stores.
Use cases: declarative passing values from stores to effects and argument preprocessing.
import {createEffect, attach, createStore} from 'effector'
const backendRequestFx = createEffect({
async handler({token, data, resource}) {
const req = fetch(`https://example.com/api${resource}`, {
method: 'POST',
headers: {
Authorization: `Bearer ${token}`,
},
body: JSON.stringify(data),
})
},
})
const $requestsSend = createStore(0).on(backendRequestFx, total => total + 1)
$requestsSend.watch(total => {
console.log(`client analytics: sent ${total} requests`)
})
const $token = createStore('guest_token')
const authorizedRequestFx = attach({
effect: backendRequestFx,
source: $token,
mapParams: ({data, resource}, token) => ({data, resource, token}),
})
const createRequestFx = resource =>
attach({
effect: authorizedRequestFx,
mapParams: data => ({data, resource}),
})
const getUserFx = createRequestFx('/user')
const getPostsFx = createRequestFx('/posts')
const user = await getUserFx({name: 'alice'})
const posts = await getPostsFx({user: user.id})
Documentation for attach
- Add
noDefaults
option for effector/babel-plugin
for making custom unit factories with clean configuration
{
"plugins": [
["effector/babel-plugin", {"addLoc": true}],
[
"effector/babel-plugin",
{
"importName": "@lib/createInputField",
"storeCreators": ["createInputField"],
"noDefaults": true
},
"createInputField"
]
]
}
import {createStore} from 'effector'
import {resetForm} from './form'
export function createInputField(defaultState, {sid, name}) {
return createStore(defaultState, {sid, name}).reset(resetForm)
}
import {createInputField} from '@lib/createInputField'
const foo = createInputField('-')
effector-react 20.6.3
- Add type support for stores with
ReadonlyArray
to useList
for typescript
effector 20.12.2
- Add type support for sample with target and without clock (in that case,
source
will become clock
as well)
import {value createStore, value sample} from 'effector'
const $a = createStore([{foo: 0}])
const $b = createStore(0)
sample({
source: $a,
target: $b,
fn: list => list.length,
})
Try it
effector-vue 20.4.0
import {createStore} from 'effector'
import {createComponent} from 'effector-vue'
const counter = createStore(0)
const component = createComponent(
{
template: '<div>{{ counter }}</div>',
watch: {
counter() {
},
},
},
{counter},
)
effector-react 20.6.2, effector-vue 20.3.3
- Fix umd build of effector-react and effector-vue
Cdn with umd build of effector-react
Cdn with umd build of effector-vue
effector 20.12.1
- Add support for guard to babel-plugin
- Add support for forward to babel-plugin
- Add support for explicit
domain.hooks
calls as escape hatch for imperative adding units to given domain
effector 20.12.0
- Add
effect.doneData
and effect.failData
events with effect result and error values as shorthands for common use cases effect.done.map(({result}) => result)
and effect.fail.map(({error}) => error)
import {createEffect, merge} from 'effector'
const fetchUserFx = createEffect()
const fetchFriendsFx = createEffect()
const apiResult = merge([fetchUserFx.doneData, fetchFriendsFx.doneData])
const apiResultOld = merge([
fetchUserFx.done.map(({result}) => result),
fetchFriendsFx.done.map(({result}) => result),
])
Try it
Documentation for effect.doneData
Documentation for effect.failData
effector 20.11.0
- Add
effect.inFlight
store to effects. It show how many effect calls aren't settled yet. Useful for rate limiting.
import {createEffect} from 'effector'
const fx = createEffect({
handler: () => new Promise(rs => setTimeout(rs, 500)),
})
fx.inFlight.watch(amount => {
console.log('in-flight requests:', amount)
})
const req1 = fx()
const req2 = fx()
await Promise.all([req1, req2])
Try it
Documentation for effect.inFlight
- Introduce
withRegion
: region-based memory management tool, which attach units (stores, events and effects) and watchers, created inside given callback to lifecycle of owner unit to be erased together with it.
import {createEvent, createDomain, withRegion} from 'effector'
const domain = createDomain()
const trigger = createEvent()
withRegion(domain, () => {
trigger.watch(n => {
console.log(n)
})
})
trigger(0)
clearNode(domain)
trigger(1)
Try it
- Add support for
Map<Store, any>
to values
property in fork
.
- Fix concurrent requests support in
effect.pending
: it will become false
only after all pending effect calls becomes settled.
effector 20.10.0
- Add
launch({target: unit, params})
overload for launch
- low level method for running computation in units (events, effects or stores). Mostly used by library developers for fine-grained control of computations.
effector 20.9.0, effector-react 20.6.0
- Introduce
effector/fork
and effector-react/ssr
: api for server side rendering and managing independent instances of application in general.
/**
* app
*/
import {value createDomain, value forward, value restore} from 'effector'
import {
value useStore,
value useList,
value Provider,
value useEvent,
} from 'effector-react/ssr'
export const app = createDomain()
const requestUsernameFx = app.createEffect<{login: string}, string>()
const requestFriendsFx = app.createEffect<string, string[]>()
const $username = restore(requestUsernameFx, 'guest')
const $friends = restore(requestFriendsFx, [])
forward({
from: requestUserName.done.map(({result: username}) => username),
to: requestFriends,
})
const Friends = () => (
<ul>
{useList($friends, friend => (
<li>{name}</li>
))}
</ul>
)
const Title = () => <header>Hello {useStore($username)}</header>
export const View = ({root}) => (
<Provider value={root}>
<Title />
<Friends />
</Provider>
)
/**
* client
*/
import ReactDOM from 'react-dom'
import {value fork} from 'effector/fork'
import {value app, value View} from './app'
// initialize app with values from server
const clientScope = fork(app, {
values: window.__initialState__,
})
ReactDOM.hydrate(<View root={clientScope} />, document.getElementById('root'))
/**
* server
*/
import express from 'express'
import {value renderToString} from 'react-dom/server'
import {value fork, value serialize, value allSettled} from 'effector/fork'
import {value app, value View} from './app'
export const server = express()
server.get('/user/:login', async (req, res) => {
// clone application
const scope = fork(app)
// call requestUsername(req.params) in scope
// and await all triggered effects
await allSettled(requestUsername, {
scope,
params: req.params, // argument for requestUsername call
})
// save all stores in application to plain object
const data = serialize(scope)
// render dom content
const content = renderToString(<View root={scope} />)
res.send(`
<body>
${content}
<script>
window.__initialState__ = ${JSON.stringify(data)};
</script>
</body>
`)
})
This solution requires effector/babel-plugin
in babel configuration:
{
"plugins": ["effector/babel-plugin"]
}
Example application with express
Serverless example
- Add events created with
createApi
, stores created with restore
and events created with .prepend
to domain of given source units
import {createDomain, createApi, restore} from 'effector'
const domain = createDomain()
domain.onCreateStore(store => {
console.log('store created')
})
domain.onCreateEvent(event => {
console.log('event created')
})
const $position = domain.createStore({x: 0})
const {move} = createApi($position, {
move: ({x}, payload) => ({x: x + payload}),
})
const $lastMove = restore(move, 0)
Try it
effector 20.8.2
- Improve
combine
batching in a few edge cases with nested combine
calls
import {createEvent, createStore, combine} from 'effector'
const event = createEvent()
const $store = createStore(0).on(event, s => s + 1)
const $combined = combine([$store, combine([$store.map(d => d + 1)])])
$combined.watch(e => fn(e))
event()
Try it
effector-react 20.5.2
- Add ability to infer
fn
argument types without as const
in useStoreMap
.
In effector-react 20.0.3 we introduced an improvement for useStoreMap
types, which helps to infer types of fn
arguments from keys
. And now useStoreMap
types improved even more: every item in second argument will have its own type even without as const
, out from a box
Type tests
useStoreMap in docs
PR #274 (thanks @abliarsar)
import React from 'react'
import {value createStore} from 'effector'
import {value useStoreMap} from 'effector-react'
type User = {
username: string
email: string
bio: string
}
const $users = createStore<User[]>([
{
username: 'alice',
email: 'alice@example.com',
bio: '. . .',
},
{
username: 'bob',
email: 'bob@example.com',
bio: '~/ - /~',
},
{
username: 'carol',
email: 'carol@example.com',
bio: '- - -',
},
])
export const UserProperty = ({id, field}: {id: number; field: keyof User}) => {
const value = useStoreMap({
store: $users,
keys: [id, field],
fn: (users, [id, field]) => users[id][field] || null,
})
return <div>{value}</div>
}
effector 20.8.0
- Allow to use objects and arrays with stores in sample source
import {createStore, createEvent, sample, combine} from 'effector'
const trigger = createEvent()
const objectTarget = createEvent()
const arrayTarget = createEvent()
const $a = createStore('A')
const $b = createStore('B')
sample({
source: {a: $a, b: $b},
clock: trigger,
target: objectTarget,
})
sample({
source: [$a, $b],
clock: trigger,
target: arrayTarget,
})
objectTarget.watch(obj => {
console.log('sampled object', obj)
})
arrayTarget.watch(array => {
console.log('sampled array', array)
})
trigger()
sample({
source: combine({a: $a, b: $b}),
clock: trigger,
target: objectTarget,
})
sample({
source: combine([$a, $b]),
clock: trigger,
target: arrayTarget,
})
Try it
effector-react 20.5.0
- Pass props to
Gate.open
& Gate.close
events
import {createGate} from 'effector-react'
const PageMeta = createGate()
PageMeta.open.watch(props => {
console.log('page meta', props)
})
const App = () => (
<>
<PageMeta name="admin page" />
<div>body</div>
</>
)
ReactDOM.render(<App />, document.getElementById('root'))
// => page meta {name: 'admin page'}
Try it
effector 20.7.0
- Add
domain.createStore
as alias for domain.store
(proposal)
- Add
domain.createEvent
as alias for domain.event
- Add
domain.createEffect
as alias for domain.effect
- Add
domain.createDomain
as alias for domain.domain
effector 20.6.2
effector 20.6.1, effector-react 20.4.1, effector-vue 20.3.2
- Add typescript typings for compat builds
- Improve built-in source maps
effector 20.6.0
- Add support for arrays to
forward
import {createEvent, forward} from 'effector'
const firstSource = createEvent()
const secondSource = createEvent()
const firstTarget = createEvent()
const secondTarget = createEvent()
forward({
from: [firstSource, secondSource],
to: [firstTarget, secondTarget],
})
firstTarget.watch(e => console.log('first target', e))
secondTarget.watch(e => console.log('second target', e))
firstSource('A')
secondSource('B')
Try it
effector-vue 20.3.0
- Add
createComponent
HOC for TypeScript usage. This HOC provides type-safe properties in vue components.
import {value createStore, value createApi} from 'effector'
import {value createComponent} from 'effector-vue'
const $counter = createStore(0)
const {update} = createApi($counter, {
update: (_, value: number) => value,
})
export default createComponent(
{
name: 'Counter',
methods: {
update,
handleClick() {
const value = this.$counter + 1
this.update(value)
},
},
},
{$counter},
)
effector 20.5.0
- Merge
createStoreObject
to combine
to reduce api surface. Wherever createStoreObject
was used, it can be replaced with combine
import {createStore, combine, createStoreObject} from 'effector'
const $r = createStore(255)
const $g = createStore(0)
const $b = createStore(255)
const $color = combine({r: $r, g: $g, b: $b})
$color.watch(console.log)
const $colorOld = createStoreObject({r, g, b})
$colorOld.watch(console.log)
Try it
- Add ability to use arrays of stores with
combine
import {createStore, combine} from 'effector'
const $r = createStore(255)
const $g = createStore(0)
const $b = createStore(255)
const $color = combine([$r, $g, $b])
$color.watch(console.log)
Try it
effector 20.4.4
- Ensure that both
effect.done
and effect.fail
are called before effect.finally
watchers, thereby preventing side-effects from interrupting pure computations
effector 20.4.3
- Throw expected error in case with
sample({clock: undefined})
import {createStore, sample} from 'effector'
sample({
source: createStore(null),
clock: undefined,
})
effector 20.4.1
effector-vue 20.2.1
const counter = createStore(0)
new Vue({
effector: {
counter,
},
})
effector 20.4.0
- Introduce
guard
: conditional event routing
Control one event with the help of another: when the condition and the data are in different places, then we can use guard with stores as a filters to trigger events when condition state is true, thereby modulate signals without mixing them
import {createStore, createEffect, createEvent, guard, sample} from 'effector'
const clickRequest = createEvent()
const fetchRequestFx = createEffect({
handler: n => new Promise(rs => setTimeout(rs, 2500, n)),
})
const $clicks = createStore(0).on(clickRequest, x => x + 1)
const $requests = createStore(0).on(fetchRequestFx, x => x + 1)
const isIdle = fetchRequestFx.pending.map(pending => !pending)
guard({
source: sample($clicks, clickRequest),
filter: isIdle,
target: fetchRequestFx,
})
See ui visualization
Also, guard
can accept common function predicate as a filter, to drop events before forwarding them to target
import {createEffect, createEvent, guard} from 'effector'
const searchUserFx = createEffect()
const submitForm = createEvent()
guard({
source: submitForm,
filter: user => user.length > 0,
target: searchUserFx,
})
submitForm('')
submitForm('alice')
Type inference
Implementation tests
- Introduce
name
property in sample
parameters list
Each basic entity in effector (event/effect/store/domain) may have a name. You now can name sampled entities in the same
manner as basic ones.
import {createStore, sample} from 'effector'
const $store = createStore(null)
const sampled = sample({
source: $store,
name: 'sampled $store',
})
console.log(sampled.shortName)
effector 20.3.2
- Allow typescript to refine type with
split
method (PR)
- Improve type inference of effects with optional arguments in Typescript (PR)
- Ensure that effect handler is called only after effect update itself, thereby preventing side-effects from interrupting pure computations
import React from 'react'
import ReactDOM from 'react-dom'
import {createStore, createEvent, createEffect, sample} from 'effector'
import {useList} from 'effector-react'
const updateItem = createEvent()
const resetItems = createEvent()
const processClicked = createEvent()
const processItemsFx = createEffect({
async handler(items) {
for (let {id} of items) {
updateItem({id, status: 'PROCESS'})
await new Promise(r => setTimeout(r, 3000))
updateItem({id, status: 'DONE'})
}
},
})
const $items = createStore([
{id: 0, status: 'NEW'},
{id: 1, status: 'NEW'},
])
.on(updateItem, (items, {id, status}) =>
items.map(item => (item.id === id ? {...item, status} : item)),
)
.on(processItemsFx, items => items.map(({id}) => ({id, status: 'WAIT'})))
.reset(resetItems)
sample({
source: $items,
clock: processClicked,
target: processItemsFx,
})
const App = () => (
<section>
<header>
<h1>Jobs list</h1>
</header>
<button onClick={processClicked}>run tasks</button>
<button onClick={resetItems}>reset</button>
<ol>
{useList($items, ({status}) => (
<li>{status}</li>
))}
</ol>
</section>
)
ReactDOM.render(<App />, document.getElementById('root'))
Try it
effector 20.3.1
- Fix edge case when
clearNode
been called on store belonged to certain domain led to the removal of the entire domain
effector-react 20.4.0
- Add support for
keys
field in useList
. By default, useList
rerenders only when some of its items was changed.
Howewer, sometimes we need to update items when some external value (e.g. props field or state of another store) is changed.
In such cases we need to tell react about our dependencies and pass keys explicitly.
import React from 'react'
import ReactDOM from 'react-dom'
import {createEvent, createStore, restore} from 'effector'
import {useStore, useList} from 'effector-react'
const renameUser = createEvent()
const $user = restore(renameUser, 'alice')
const $friends = createStore(['bob'])
const List = () => {
const userName = useStore($user)
return useList($friends, {
keys: [userName],
fn: friend => (
<div>
{friend} is a friend of {userName}
</div>
),
})
}
ReactDOM.render(<List />, document.getElementById('root'))
// => <div> bob is a friend of alice </div>
setTimeout(() => {
renameUser('carol')
// => <div> bob is a friend of carol </div>
}, 500)
Try it
effector 20.3.0
import {createDomain} from 'effector'
const domain = createDomain('feature')
console.log(domain.shortName)
Try it
- Add
history
to domains with read-only sets of events, effects, stores and subdomains
import {createDomain} from 'effector'
const domain = createDomain()
const eventA = domain.event()
const $storeB = domain.store(0)
console.log(domain.history)
Try it
effector-vue 20.2.0
- Add support for object shape
const counter = createStore(0)
new Vue({
effector: {
counter,
},
})
effector 20.2.0
- Add support for domains to
clearNode
import {createDomain, clearNode} from 'effector'
const root = createDomain()
const child = root.domain()
clearNode(child)
- Add
.sid
- stable hash identifier for events, effects, stores and domains, preserved between environments, to handle client-server interaction within the same codebase.
import {createEffect} from 'effector'
export const getUserFx = createEffect({sid: 'GET /user'})
console.log(getUsers.sid)
import {getUsers} from './common'
getUsers.use(userID => fetch(userID))
getUsers.done.watch(({result}) => {
postMessage({sid: getUsers.sid, result})
})
onmessage = async ({data}) => {
if (data.sid !== getUsers.sid) return
getUsers(data.userID)
}
import {createEvent} from 'effector'
import {getUsers} from './common'
const onMessage = createEvent()
const worker = new Worker('worker.js')
worker.onmessage = onMessage
getUsers.use(
userID =>
new Promise(rs => {
worker.postMessage({sid: getUsers.sid, userID})
const unwatch = onMessage.watch(({data}) => {
if (data.sid !== getUsers.sid) return
unwatch()
rs(data.result)
})
}),
)
The key is that sid can be autogenerated by effector/babel-plugin
with default config and it will be stable between builds
See example project
- Add support for implicit void params in
createEffect
for typescript #106
const handler = () => console.log()
const fx = createEffect({handler})
fx()
- Fix bug with
cannot read property .toString of undefined
error during store initialization
effector-react 20.3.0
- Add support for react hooks in
createComponent
effector-react 20.2.2, effector-vue 20.1.2
effector-react
, effector-vue
and effector
itself have compat builds for compatibility with old devices without babel. In such versions, it should import effector/compat
, not just effector
(Fix #173)
effector 20.1.2
- Allow typescript to refine type of payload if
event.filter({fn})
got a predicate function as a callback PR
import {value createEvent} from 'effector'
const event = createEvent<string | number>()
const isString = (value: any): value is string => typeof value === 'string'
const isNumber = (value: any): value is number => typeof value === 'number'
const str = event.filter({fn: isString})
const num = event.filter({fn: isNumber})
str.watch(value => value.slice())
num.watch(value => value.toFixed(2))
- Allow typescript to refine type with
is
methods PR
import {value is} from 'effector'
function getEvent(obj: unknown) {
if (is.event(obj)) return obj
if (is.store(obj)) return obj.updates
}
- Add new fields to definition of graph nodes (discussion)
effector 20.1.1
- Add support for IE11 to
effector/compat
- Fix flow typings for
sample
- Allow
effector/babel-plugin
to work in browser
effector-react 20.2.1, effector-vue 20.1.1
- Add support for IE11 to
effector-react/compat
and effector-vue/compat
effector 20.1.0
- Add
effector/compat
module to use with Smart TV (Chrome 47) apps without babel (fix #152). Starting with this release, the library code is tested by browserstack.com for compatibility with our targets, including smart tv
- Improve typescript typings for
sample
(thanks @abliarsar) (PR #156)
- Fix webpack issue, which generated incorrect code with some ancient targets (IE10)
effector-react 20.2.0
- Add
effector-react/compat
module to use with Smart TV (Chrome 47) apps without babel
effector-vue 20.1.0
- Add
effector-vue/compat
module to use with Smart TV (Chrome 47) apps without babel
effector-react 20.1.1
- Add
useList
for efficient rendering of store lists
import React from 'react'
import ReactDOM from 'react-dom'
import {createStore} from 'effector'
import {useList} from 'effector-react'
const $list = createStore([
{name: 'alice', age: 21},
{name: 'bob', age: 20},
{name: 'carol', age: 22},
])
const List = () => {
const users = useList($list, ({name}, i) => (
<div>
{i}) {name}
</div>
))
return <div>{users}</div>
}
ReactDOM.render(<List />, document.getElementById('root'))
Try it
effector-react 20.0.5
- Fix irrelevant react memory leak warning in a few cases
effector-react 20.0.4
- Fix a bug in
useStore
with lack of store updates triggered by react hooks in children components
effector-react 20.0.3
- Allow
as const
typescript assertion for useStoreMap
keys. It helps us to infer type for fn
arguments
import React from 'react'
import {value createStore} from 'effector'
import {value useStoreMap} from 'effector-react'
type User = {
username: string
email: string
bio: string
}
const $users = createStore<User[]>([
{
username: 'alice',
email: 'alice@example.com',
bio: '. . .',
},
{
username: 'bob',
email: 'bob@example.com',
bio: '~/ - /~',
},
{
username: 'carol',
email: 'carol@example.com',
bio: '- - -',
},
])
export const UserProperty = ({id, field}: {id: number; field: keyof User}) => {
const value = useStoreMap({
store: $users,
keys: [id, field] as const,
fn: (users, [id, field]) => users[id][field] || null,
})
return <div>{value}</div>
}
In typescript versions below 3.4, you can still use an explicit type assertion
import React from 'react'
import {value createStore} from 'effector'
import {value useStoreMap} from 'effector-react'
type User = {
username: string
email: string
bio: string
}
const $users = createStore<User[]>([
{
username: 'alice',
email: 'alice@example.com',
bio: '. . .',
},
{
username: 'bob',
email: 'bob@example.com',
bio: '~/ - /~',
},
{
username: 'carol',
email: 'carol@example.com',
bio: '- - -',
},
])
export const UserProperty = ({id, field}: {id: number; field: keyof User}) => {
const value = useStoreMap({
store: $users,
keys: [id, field] as [number, keyof User],
fn: (users, [id, field]) => users[id][field] || null,
})
return <div>{value}</div>
}
as const in typescript docs
effector-react 20.0.2
- Fix bug with additional rerender in case of
useStore
argument change
effector-react 20.0.1
- Fix flow typings for
useStoreMap
effector 20.0.0
- Add
merge
for merging events
import {createEvent, merge} from 'effector'
const foo = createEvent()
const bar = createEvent()
const baz = merge([foo, bar])
baz.watch(v => console.log('merged event triggered: ', v))
foo(1)
bar(2)
Try it
- Add
split
for pattern-matching over events
import {createEvent, split} from 'effector'
const message = createEvent()
const messageByAuthor = split(message, {
bob: ({user}) => user === 'bob',
alice: ({user}) => user === 'alice',
})
messageByAuthor.bob.watch(({text}) => {
console.log('[bob]: ', text)
})
messageByAuthor.alice.watch(({text}) => {
console.log('[alice]: ', text)
})
message({user: 'bob', text: 'Hello'})
message({user: 'alice', text: 'Hi bob'})
const {__: guest} = messageByAuthor
guest.watch(({text}) => {
console.log('[guest]: ', text)
})
message({user: 'unregistered', text: 'hi'})
Try it
- Allow
clearNode
to automatically dispose all related intermediate steps
import {createEvent, clearNode} from 'effector'
const source = createEvent()
const target = source.map(x => {
console.log('intermediate step')
return x
})
target.watch(x => console.log('target watcher'))
source()
clearNode(target)
source()
Try it
import {createEffect} from 'effector'
const fetchApiFx = createEffect({
handler: n =>
new Promise(resolve => {
setTimeout(resolve, n, `${n} ms`)
}),
})
fetchApiFx.finally.watch(response => {
console.log(response)
})
await fetchApiFx(10)
Try it
- Add types for createEvent with config instead of string
- Add types for createEffect with config instead of string
- Add
event.filterMap
as new alias for event.filter(fn)
- Remove
extract
, withProps
, is.*
re-exports
effector-react 20.0.0
- Removed unstable_createStoreProvider
effector-vue 20.0.0
Vue adapter for effector 20
effector-react 19.1.2
- Add
useStoreMap
hook to select part from a store. Motivation
import {createStore} from 'effector'
import {useStore, useStoreMap} from 'effector-react'
import React from 'react'
import ReactDOM from 'react-dom'
const User = ({id}) => {
const user = useStoreMap({
store: $users,
keys: [id],
fn: (users, [id]) => users[id],
})
return (
<div>
{user.name} ({user.age})
</div>
)
}
const UserList = () => useStore(userID$).map(id => <User id={id} key={id} />)
const $user = createStore({
alex: {age: 20, name: 'Alex'},
john: {age: 30, name: 'John'},
})
const $userID = $user.map(users => Object.keys(users))
ReactDOM.render(<UserList />, document.getElementById('root'))
Try it
effector 19.1.0
- Add support for
event.filter
with common predicate functions
import {createEvent} from 'effector'
const event = createEvent()
const filtered = event.filter({
fn: x => x > 0,
})
filtered.watch(x => console.log('x =', x))
event(-2)
event(2)
effector-vue 19.0.1
- Fix typescript typings #116
effector, effector-react, effector-vue 19.0.0
To indicate the stability of the project, we adopting semantic versioning and happy to announce version 19.0.0 for all packages. And to make the transition easier, that release contains no breaking changes; simple replacement of "^0.18.*" to "^19.0.0" is safe for sure ☄️
effector 0.18.10-0.18.11
- Implement event
store.updates
, representing updates of given store. Use case: watchers, which will not trigger immediately after creation (unlike store.watch
)
see spec for store.updates
in tests
import {createStore, is} from 'effector'
const $clicksAmount = createStore(0)
is.event($clicksAmount.updates)
$clicksAmount.watch(amount => {
console.log('will be triggered with current state, immediately, sync', amount)
})
$clicksAmount.updates.watch(amount => {
console.log('will not be triggered unless store value is changed', amount)
})
Try it
effector 0.18.9
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()
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)
const clickTitle = createEvent()
console.log('event.shortName', clickTitle.shortName)
const Title = createComponent({title: $title}, (props, title) => (
<h1>{title}</h1>
))
console.log('Component.displayName', Title.displayName)
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)
effector-react 0.18.10
- Add initial props factory to
createComponent
import {users} from './feature'
const UserItem = createComponent(
initialProps => users.map(users => users[initialProps.id]),
(_, user) => {
return <div>{user.username}</div>
},
)
const UserList = createComponent(users, (_, users) => {
return users.map(user => <TodoItem key={user.id} id={user.id} />)
})
- Implicitly convert objects to
createStoreObject
in createComponent
const deposit = createEvent()
const $username = createStore('zerobias')
const $balance = createStore(0)
const Profile = createComponent(
{username: $username, balance: $balance},
(_, {username, balance}) => {
return (
<div>
Hello, {username}. Your balance is {balance}
<button onClick={deposit}>Deposit</button>
</div>
)
},
)
- Add
mounted
and unmounted
events to components created by createComponent
import {counter, increment} from './feature'
const Counter = createComponent(counter, (_, state) => {
return (
<div>
{state}
<button onClick={increment}>+</button>
</div>
)
})
Counter.mounted.watch(({props, state}) => {
counter.on(increment, s => s + 1)
})
Counter.unmounted.watch(({props, state}) => {
counter.off(increment)
})
- Replace
useLayoutEffect
with useIsomorphicLayoutEffect
to support server-side rendering
effector-react 0.18.9
- Replace
useEffect
with useLayoutEffect
in useStore
hook to response to state changes immediately
0.18.5-0.18.6
- Optimize combined stores: no intermediate steps no more
import {createStore, createEvent, createStoreObject, combine} from 'effector'
const updateField = createEvent('update $field value')
const $field = createStore('').on(updateField, (state, upd) => upd.trim())
const $isEmpty = $field.map(value => value.length === 0)
const $isTooLong = $field.map(value => value.length > 12)
const $isValid = combine(
$isEmpty,
$isTooLong,
(isEmpty, isTooLong) => !isEmpty && !isTooLong,
)
createStoreObject({
field: $field,
isEmpty: $isEmpty,
isTooLong: $isTooLong,
isValid: $isValid,
}).watch(data => {
console.log(data)
})
updateField('bobby')
import {createStore, createEvent, is} from 'effector'
const $store = createStore('value')
const event = createEvent('some event')
is.store($store)
is.event($store)
is.unit($store)
is.store(event)
is.event(event)
is.unit(event)
is.store(null)
is.event(null)
is.unit(null)
Add clearNode
to break references and subscriptions between events, stores, etc
Add support for custom datatypes by making step
constructors, createNode
and launch
functions public
import {createNode, launch, step, createStore} from 'effector'
const $target = createStore(0)
$target.watch(n => console.log('current n = ', n))
const customNode = createNode({
scope: {max: 100, lastValue: -1, add: 10},
child: [$target],
node: [
step.compute({
fn: (arg, {add}) => arg + add,
}),
step.filter({
fn: (arg, {max, lastValue}) => arg < max && arg !== lastValue,
}),
step.compute({
fn(arg, scope) {
scope.lastValue = arg
return arg
},
}),
],
})
launch(customNode, 3)
launch(customNode, 95)
launch(customNode, 5)
launch(customNode, 5)
- Fix
fromObservable
, ensure it works with redux
as a typical library with Symbol.observable
support
import {fromObservable} from 'effector'
import * as redux from 'redux'
const INCREMENT_STATE = 'INCREMENT_STATE'
const reduxStore = redux.createStore((state = 1, action) => {
switch (action.type) {
case INCREMENT_STATE:
return state + 1
default:
return state
}
})
const updateEvent = fromObservable(reduxStore)
updateEvent.watch(state => {
console.log('redux state = ', state)
})
reduxStore.dispatch({type: INCREMENT_STATE})
- Fix
version
, now it always equals version in package.json
import {version} from 'effector'
console.log(version)
- Add support forwarding to effects
import {createEffect, createEvent, forward} from 'effector'
const trigger = createEvent()
const fx = createEffect('side-effect', {
async handler(args) {
await new Promise(rs => setTimeout(rs, 500))
console.log('args: ', args)
},
})
forward({
from: trigger,
to: fx,
})
trigger('payload')
0.18.3-0.18.4
- Add version variable to public exports
import {version} from 'effector'
console.log(version)
Add effect handler to domain 4c6ae8
Add Unit<T>
as common interface implemented by Event
, Effect
and Store
Add isStore
, isEvent
, isEffect
and isUnit
validators
import {createStore, createEvent, isStore, isEvent, isUnit} from 'effector'
const event = createEvent('some event')
const $store = createStore('value')
isStore($store)
isEvent($store)
isUnit($store)
isStore(event)
isEvent(event)
isUnit(event)
isStore(null)
isEvent(null)
isUnit(null)
- Add extended
createStore
with config
import {createStore} from 'effector'
const $store = createStore('value', {
name: 'value store',
})
Publish babel-plugins
Improve naming for chrome performance timeline
Fix typescript typings #45
Fix event.prepend
bug #35
0.18.2
Fix webpack usage issue. To prevent this in a future, webpack integration test was added.
Improve typescript typings for createApi
. This code example became type checked
import {createStore, createApi} from 'effector'
const $text = createStore('')
const {addMessage, cut} = createApi($text, {
addMessage: (text, message) => text + `\n` + message
cut: (text, {fromIndex, size}) => text.slice(fromIndex, fromIndex + size),
})
- Add umd bundle to npm. Therefore, you can use cdn to include library without bundlers
<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/effector@0.18.2/effector.umd.js"></script>
</head>
<body>
<script>
const header = document.createElement('h1')
document.body.appendChild(header)
const $text = effector.createStore('hello')
$text.watch(str => (header.innerHTML = str))
</script>
</body>
</html>
0.18.1
- Add
forward
: common function for forwarding updates and events
import {forward} from 'effector'
const unsubscribe = forward({
from: Event | Store,
to: Event | Store | Effect,
})
- add support for storages in
store.on
import {createStore} from 'effector'
const $name = createStore('name')
const $counter = createStore(0).on(name, (count, name) => count++)
- Allow to pass
{handler: Function}
as second argument to createEffect
import {createEffect} from 'effector'
const callApiFx = createEffect('call api', {
async handler(url) {
const res = await fetch(url)
return res
},
})
- Make
effect.use
return the same effect instead of void (ability to chain method calls)
import {createEffect} from 'effector'
const callApiFx = createEffect('call api').use(url => fetch(url))
0.18.0
- Log events into Chrome devtools performance timeline
- Add notifications about errors inside computation chain
- Add
store.defaultState
property
- effector-react: Add
createComponent
- Make
withProps
static function
- Make effect return plain promise
0.18.0-beta.10
import {type Gate, createGate} from 'effector-react'
const AppGate = createGate('app')
const MainPageGate = AppGate.childGate('main page')
export default ({isLoading, meta}) => (
<div>
Application
<AppGate isLoading={isLoading} />
{!isLoading && (
<div>
Main page
<MainPageGate meta={meta} />
</div>
)}
</div>
)
AppGate.state.watch(({isLoading}) => isLoading)
0.17.7
- Keep and replay the whole domain history for every new hook
0.17.6
- Add domain hooks for handle new events, effects or stores in domain.
import {createDomain} from 'effector'
const mainPage = createDomain('main page')
mainPage.onCreateEvent(event => {
console.log('new event: ', event.getType())
})
mainPage.onCreateStore(store => {
console.log('new store: ', store.getState())
})
const mount = mainPage.event('mount')
const pageStore = mainPage.store(0)
- Improve TypeScript typings
0.17.5
- Add ability to use createEvent, createEffect and createDomain without arguments (omit name)
- Fix wrong order of effect names
- Add
createWrappedDomain
to watch all nested events and updates
- Add
extract
to watch only part of nested storages
- Deprecate
.epic
method (library supports symbol-observable, so assumed that most.from(event)
or Observable.Of(store)
covered all use cases)
0.17.4
- effector-react: Add check for mounting of store consumer
- Add
effect.use.getCurrent()
method to get current used function
- Improve type inference in flow typing for
createStoreObject
- Improve public ts and flow typings
0.17.3
- Fix effector-react typings
- Build with node 6 target, add engine field to package.json
- Add warning dependency
0.17.2
- Memoize store.map and store updates
0.17.0
- Added sync graph reduction engine (it's internal)
- Added store updates memoization
- Introduced effector-react
0.16.0
- Removed most-subject dependency
- New api
0.15.0-rc.2
- Add AVar: low-level interface for asynchronous variables
- Clean up builds before publishing
- Add types dir into npm build
0.14.0
- Add independent
createStore
method
- Replace console.warn with console.error in warnings
- Make reducers full-featured store elements (add
.get()
, .set(x)
and .map(fn)
methods)
- Add observable declaration to effects, events and reducers, which allow interop in this way:
from(effect)
0.13.0
- Build via rollup
- New module architechture
0.12.0
- Exclude coverage from npm build
- Rename
mill
to collect
- Rename
joint
to combine
0.11.1
- Remove source files from npm release
0.11.0
- Add support for sync functions in
.use
- breaking Rename config option
effectImplementationCheck
to unused
0.10.2
- Fix overriding of flow modules
0.10.0
- breaking Removed
rootDomain
alias for createRootDomain
- Fixed duplication of
typeConstant
events
- Added sync event propagation
- Catching of watch function errors
- Added warning to port errors
- Added type aliases
DomainAuto
, EventAuto
and EffectAuto
- Added
mill
fluent "AND" reducer combinator
import {mill, type MillType, type Reducer} from 'effector'
type A = 'foo'
type B = 'bar'
declare var reducerA: Reducer<A>
declare var reducerB: Reducer<B>
const tuple: MillType<A, B> = mill().and(reducerA).and(reducerB)
const union: Reducer<{
a: A,
b: B,
staticField: string,
}> = tuple.joint((a: A, b: B) => ({
a,
b,
staticField: 'its ok',
}))
0.9.1
- Added hot reload support for root domains
- Added support for dispatching halt action
import {createHaltAction} from 'effector'
store.dispatch(createHaltAction())
0.9.0
First stable version
Before 0.9.0
Proof of concept