Skip to content

Deprecate undefined as a magic skip update value and allow it as a normal value #920

Closed
@sergeysova

Description

@sergeysova

Background

There is an ancient feature in the effector - when undefined is returned from some reducer, it reads as skip update command and store does not update its state.
The idea was to make every reducer a kind of filterMap thing, which, in theory, can be handy sometimes, but in practice this feature is basically almost not used at all.

Its have few consequences:

  • undefined basically cannot be used as a state of the store. createStore(undefined) will throw.
  • Mapped stores are becoming "kind of stateful" - they do not have direct access to previous state, but still can do basically return previousState via undefined

Basically, now it is a outdated and confusing design desicion, which is to be removed.

Explanation

As per effector's Releases Policy, every breaking change must be moved through deprecation period first.
But just deprecating it with a warning is not an option, as this way we basically will lose the possibility to use undefined as a value in stores in any way - basically it will become sort of UB, which is weird.

This means, we need a graceful way to change the semantics of undefined usage in reducers.

To do so, we need to introduce a separate configuration, which will set this behavior to specific option.

After that, in the effector 24, we will be able to change the default setting and deprecate skipVoid: true.

And in the effector 25 finally get rid of this feature at all.

Examples

Derived stores

In effector 23 this code will show a warning, requiring the user to explicitly set skipVoid setting in the configuration, while keeping the old filterMap-like behavior.

No config

Should skip update and show a warning, requiring the user to explicitly provide the configuration

$store.map(s => s ? 42 : undefined)

Explicit skipVoid: false

This code will turn off filterMap-like behavoir and will allow undefined to pass further as a value

$store.map(s => s ? 42 : undefined, { skipVoid: false })

Explicit skipVoid: true

Will silenece the warning and keep current behaviour (skip of update)

$store.map(s => s ? 42 : undefined, { skipVoid: true })

Not affected case

The code, which does not use undefined in any way, will not require any configuration

$store.map(s => s ? 42 : null)

The same applies to combine

Base stores

In effector 23 createStore declaration with undefined as a base value should still throw, just like all versions before, but this time undefined as a store value can be allowed as manual { skipVoid: false } configuration.

Also, in reducers and samples, that are going to write undefined into store, warning, similiar to the one of the combine and map, should be shown

Not affected case

Those stores, which are not using undefined in any way, are not affected by this change

const $store = createStore<SomeObject | null>(null)

Store declaration with void or undefined

Throws immediatly with message like "To allow undefined value in store add { skipVoid: false } into the config

const $storeA = createStore()
const $storeB = createStore(undefined)

Writing undefined into store

Skips update and shows warning, requiring the user to explicitly set skipVoid setting in the store configuration OR return previous state to explicitly skip update

$store.on(event, () => undefined)
$store.on(event, () => {
 // nothing
})

sample({
 clock: event,
 fn: () => {
   // nothing
 },
 target: $store,
})

Explicit skipVoid: false

Explicit skipVoid: false allows to use undefined as a value in this store in all cases

const $store = createStore(undefined, {skipVoid: false})

$store.on(event, () => undefined)
$store.on(event, () => {
 // nothing
})

sample({
 clock: event,
 fn: () => {
   // nothing
 },
 target: $store,
})

Explicit skipVoid: true

Keeps current behaviour AND mutes all the warnings

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions