The state manager ☄️

Overview

☄️ effector

The state manager

Table of Contents

Introduction

Effector is an effective multi-store state manager for Javascript apps (React/React Native/Vue/Node.js), that allows you to manage data in complex applications without the risk of inflating the monolithic central store, with clear control flow, good type support and high capacity API. Effector supports both TypeScript and Flow type annotations out of the box.

Effector follows five basic principles:

  • Application stores should be as light as possible - the idea of adding a store for specific needs should not be frightening or damaging to the developer.
  • Application stores should be freely combined - data that the application needs can be statically distributed, showing how it will be converted in runtime.
  • Autonomy from controversial concepts - no decorators, no need to use classes or proxies - this is not required to control the state of the application and therefore the api library uses only functions and plain js objects
  • Predictability and clarity of API - a small number of basic principles are reused in different cases, reducing the user's workload and increasing recognition. For example, if you know how .watch works for events, you already know how .watch works for stores.
  • The application is built from simple elements - space and way to take any required business logic out of the view, maximizing the simplicity of the components.

Installation

npm install --save effector
# or
yarn add effector

React

npm install --save effector effector-react
# or
yarn add effector effector-react

Vue

npm install --save effector effector-vue
# or
yarn add effector effector-vue

Svelte

Svelte works with effector out from a box, no additional packages needed. See word chain game application written with svelte and effector.

CDN

Documentation

For additional information, guides and api reference visit our documentation site

Packages

Package Version Size
effector npm-effector size-effector
effector-react npm-react size-react
effector-vue npm-vue size-vue

Articles

Community

Online playground

You can try effector in our repl

Code sharing, Typescript and react supported out of the box. REPL repository

DevTools

Use effector-logger for printing updates to console, displaying current store values with ui or connecting application to redux devtools

Examples

Increment/decrement with React

import {createStore, createEvent} from 'effector'
import {useStore} from 'effector-react'

const increment = createEvent()
const decrement = createEvent()
const resetCounter = createEvent()

const counter = createStore(0)
  .on(increment, state => state + 1)
  .on(decrement, state => state - 1)
  .reset(resetCounter)

counter.watch(console.log)

const Counter = () => {
  const value = useStore(counter)
  return <div>{value}</div>
}

const App = () => {
  const value = useStore(counter)

  return (
    <>
      <Counter />
      <button onClick={increment}>+</button>
      <button onClick={decrement}>-</button>
      <button onClick={resetCounter}>reset</button>
    </>
  )
}

Run example


Hello world with events and nodejs

const {createEvent} = require('effector')

const messageEvent = createEvent()

messageEvent.watch(text => console.log(`new message: ${text}`))

messageEvent('hello world')
// => new message: hello world

Run example


Stores and events

const {createStore, createEvent} = require('effector')

const turnOn = createEvent()
const turnOff = createEvent()

const status = createStore('offline')
  .on(turnOn, () => 'online')
  .on(turnOff, () => 'offline')

status.watch(newStatus => {
  console.log(`status changed: ${newStatus}`)
})
// for store watchs callback invokes immediately
// "status changed: offline"

turnOff() // nothing has changed, callback is not triggered
turnOn() // "status changed: online"
turnOff() // "status changed: offline"
turnOff() // nothing has changed

Run example


More examples

API

Event

Event is an intention to change state.

import {createEvent} from 'effector'
const send = createEvent() // unnamed event
const onMessage = createEvent('message') // named event

const socket = new WebSocket('wss://echo.websocket.org')
socket.onmessage = msg => onMessage(msg)
socket.onopen = () => send('{"text": "hello"}')

const onMessageParse = onMessage.map(msg => JSON.parse(msg.data))

onMessageParse.watch(data => {
  console.log('Message from server ', data)
})

send.watch(data => {
  socket.send(data)
})

Run example

Effect

Effect is a container for async function. It can be safely used in place of the original async function.

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()
})

// subscribe to pending store status
fetchUserReposFx.pending.watch(pending => {
  console.log(pending) // false
})

// subscribe to handler resolve
fetchUserReposFx.done.watch(({params, result}) => {
  console.log(params) // {name: 'zerobias'}
  console.log(result) // resolved value
})

// subscribe to handler reject or throw error
fetchUserReposFx.fail.watch(({params, error}) => {
  console.error(params) // {name: 'zerobias'}
  console.error(error) // rejected value
})

// subscribe to both cases
fetchUserReposFx.finally.watch(data => {
  if (data.status === 'done') {
    const {params, result} = data
    console.log(params) // {name: 'zerobias'}
    console.log(result) // resolved value
  } else {
    const {params, error} = data
    console.error(params) // {name: 'zerobias'}
    console.error(error) // rejected value
  }
})

// you can replace handler anytime
fetchUserReposFx.use(requestMock)

// calling effect will return a promise
const result = await fetchUserReposFx({name: 'zerobias'})

Run example

Store

Store is an object that holds the state tree. There can be multiple stores.

// `getUsers` - is an effect
// `addUser` - is an event
const users = createStore([{ name: Joe }])
  // subscribe store reducers to events
  .on(getUsers.done, (oldState, payload) => payload)
  .on(addUser, (oldState, payload) => [...oldState, payload]))

// subscribe to store updates
users.watch(state => console.log(state)) // `.watch` for a store is triggered immediately: `[{ name: Joe }]`
// `callback` will be triggered each time when `.on` handler returns the new state

Store composition/decomposition

Most profit thing of stores.

Get smaller part of the store:

// `.map` accept state of parent store and return new memoized store. No more reselect ;)
const firstUser = users.map(list => list[0])
firstUser.watch(newState => console.log(`first user name: ${newState.name}`)) // "first user name: Joe"

addUser({name: Joseph}) // `firstUser` is not updated
getUsers() // after promise resolve `firstUser` is updated and call all watchers (subscribers)

Compose stores:

import {createStore, combine} from 'effector'

const a = createStore(1)
const b = createStore('b')

const c = combine({a, b})

c.watch(console.log)
// => {a: 1, b: "b"}

See combine in docs

Run example

Domain

Domain is a namespace for your events, stores and effects. Domain can subscribe to event, effect, store or nested domain creation with onCreateEvent, onCreateStore, onCreateEffect, onCreateDomain(to handle nested domains) methods.

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.createEvent('mount')
// => new event: main page/mount

const pageStore = mainPage.createStore(0)
// => new store: 0

See Domain in docs

Run example

See also worker-rpc example, which uses shared domain for effects

Learn more

Support us

More articles about effector at patreon

Tested with browserstack

Tested with browserstack

Contributors


Dmitry

💬 💻 📖 💡 🤔 🚇 ⚠️

andretshurotshka

💬 💻 📖 📦 ⚠️

Sergey Sova

📖 💡 💻 ⚠️ 🤔

Arutyunyan Artyom

📖 💡

Ilya

📖

Arthur Irgashev

📖 💻 💡

Igor Ryzhov

📖 💻 💡

Egor Guscha
📖

bakugod
📖 💡

Ruslan
📖 💻 🤔 ⚠️

Maxim Alyoshin
📖

Andrey Gopienko
📖

Vadim Ivanov
📖

Aleksandr Anokhin
💻

Anton Kosykh
💻

Konstantin Lebedev
💡

Pavel Tereschenko
💻

Satya Rohith
📖

Vladislav Melnikov
💻

Grigory Zaripov
💻

Marina Miyaoka
💻

Evgeny Zakharov
📖

Viktor

💻 📖 ⚠️ 🤔

Ivan Savichev

💻 🤔

Nikita Nafranets

📖 💡

Tauyekel Kunzhol

📖

Andrew Laiff

📖

Illia Osmanov

💻 🤔

Yan

📖

Egor Aristov

📖

Sozonov

📖

Rafael Fakhreev

💻 🤔 ⚠️

Victor

💻 🤔 📖

Dmitrij Shuleshov

📖

Valeriy Kobzar

💻 🚇 🤔

Ivan

💻 ⚠️

Aleksandr Osipov

📖 ⚠️

popuguy

📖 🚇 🤔

uulaal

💻

Viktor Pasynok

🚇 💻 ⚠️

License

MIT

Comments
  • Method `when`

    Method `when`

    Sometimes you need to enable logic only when condition is met.

    Proposal

    Is to add new method when enables logic inside callback to work only when condition is met:

    import { when, createStore, combine, createEvent, sample } from 'effector';
    
    export const $authorized = createStore(false);
    
    const pageMounted = createEvent();
    const $counter = createStore(0);
    
    when($authorized, () => {
      $counter.on(pageMounted, (counter) => counter + 1);
      // or
      sample({
        source: $counter,
        clock: pageMounted,
        fn: counter => counter + 1,
        target: $counter,
      })
    })
    

    Use case

    Without this method each operator should be wrapped with guard

    import { when, createStore, combine, createEvent, sample, guard } from 'effector';
    
    export const $authorized = createStore(false);
    
    const pageMounted = createEvent();
    const $counter = createStore(0);
    
    // Cannot be used, cause it works always
    // $counter.on(pageMounted, (counter) => counter + 1);
    
    sample({
      source: $counter,
      clock: guard(pageMounted, { filter: $authorized }),
      fn: counter => counter + 1,
      target: $counter,
    })
    
    RFC 
    opened by sergeysova 20
  • Documentation: Valid use-cases for `Store#getState()`

    Documentation: Valid use-cases for `Store#getState()`

    I'm creating a NodeJS web server backend API that aggregates state with Effector. It works great, but it seems that I must use .getState on my stores in order to actually return the data to the client when requested. Are there any problems with this? Is there a better way to use store state in request responses?

    question 
    opened by supafreq 14
  • Loss of the scope on the browser side

    Loss of the scope on the browser side

    What is the current behavior: Looks like the scope loses on the browser side

    Please provide the steps to reproduce and if possible a minimal demo of the problem via https://share.effector.dev, https://codesandbox.io or similar My app is based on Next.js. Will try describe some components and logic in my app to understand the situation. It is not complex. So, there are some routes in my app. For now we are interested in two of them: /account and /account/edit. The route /account/edit contains component AccountEdit like this

    Pasted Graphic 1 So, just a form and effect `updateAccountInfoFx` to send form data to an API. (Just to clarify - the store `$account` fills on the SSR side via an effect that wraps an API endpoint.) Also, there is the `sample` sample( config So, after successfull sending to API will be displayed a notification in UI. `setNotification` fills the store `$notification`.

    There is a component DefaultLayout that wraps all pages and render the notification like this

    Pasted Graphic 4 The introductory information is over. Now will be the issue. If we open the route `/account/edit` directly and update data in the form then the notification will be displayed. Here is a short demo [iCloud link 1](https://www.icloud.com/iclouddrive/04djR8FExAUpheAckrYJx0a4g#%D0%97%D0%B0%D0%BF%D0%B8%D1%81%D1%8C_%D1%8D%D0%BA%D1%80%D0%B0%D0%BD%D0%B0_2021-08-20_%D0%B2_13.49.08)

    If we open the route /account and then go to the route /account/edit via Next.js routing, then again update data in the form, so after submitting the notification will not be displayed. Here is a short demo iCloud link 2

    Hope everything was clear.

    What is the expected behavior: The scope should be the same on the browser side and SSR side

    Which versions of effector packages, and which browser and OS are affected by this issue? Did this work in previous versions of effector?: The issue is available in effector version 21.8.12-b75df7cb and effector-react 21.3.3-b75df7cb. There is no issue in the version effector 21.8.11 and effector-react 21.3.2

    bug effector-react/scope nextjs 
    opened by smenshikov 14
  • useStoreMap is broken with React 18.

    useStoreMap is broken with React 18.

    What is the current behavior: With react 17 everything is fine, with react 18 (which was just released) useStoreMap doesn't work.

    const works = useStore($myStore)
    const doesntWork = useStoreMap($myStore, x => x)
    

    What is the expected behavior: works and doesntWork should give the same result, since useStoreMap uses identity function as mapping.

    Which versions of effector packages, and which browser and OS are affected by this issue? Did this work in previous versions of effector?:

    effector: 22.2.0
    effector-react: 22.0.6
    
    bug effector-react 
    opened by mendrik 13
  • Effector react: unmounted component

    Effector react: unmounted component

    What is the current behavior:

    I'm getting a react error while modifying a store value on fx.done

      | printWarning | @ | react-dom.development.js:67 -- | -- | -- | --   | error | @ | react-dom.development.js:43   | warnAboutUpdateOnUnmountedFiberInDEV | @ | react-dom.development.js:23914   | scheduleUpdateOnFiber | @ | react-dom.development.js:21840   | dispatchAction | @ | react-dom.development.js:16139   | o2 | @ | apiBase.ts:131   | (anonymous) | @ | apiBase.ts:102   | fn | @ | createWatch.ts:8   | et | @ | kernel.ts:526   | o | @ | kernel.ts:389   | create | @ | createUnit.ts:151   | r2 | @ | createUnit.ts:142   | onFocus | @ | VisualNode.tsx:59

    What is the expected behavior:

    is that a problem with resolving promises in unmounted components? Since I don't use useEffect myself this seems like a bug in the library

    "effector": "22.1.2", "effector-react": "22.0.5"

    bug effector-react 
    opened by mendrik 13
  • Better documentation for `Store.map`

    Better documentation for `Store.map`

    map(fn: (state: State, lastState?: T) => T)

    We discussed this question a bit in community.

    From my point of view lastState is not the best name for the second fn argument, because it actually contains NOT the last (previous as someone may think) state of current store, but current state of a computed one. This is significant diffenece IMO and may discourage. Though it is pretty clear from typings (lastState has type T, not State), someone may experience cognitive dissonance :)

    What do you think about map(fn: (state: State, lastComputedState?: T) => T) and map(fn: (state: State, lastComputedState: T) => T, initialComputedState: T) ?

    Arguments section

    (-) fn (Function): Function that receives state and lastState? and returns a new state for the derived store (+) fn (Function): Function that receives state and lastComputedState? and returns a new computed state for the derived store. (+) initialComputedState (T): Provide initial value for the lastComputedState argument (which has undefined value during the first store emission by default)

    Examples

    I think, adding an additional simpe exampe in the manner of const sumStore = numbersStore.map((n, sum) => sum + n, 0) will be enough for people to understand the gist. This example shows similarity with reducer operation everyone already knows.

    ========================

    Will be glad to receive feedback)

    documentation 
    opened by bloadvenro 13
  • Compatibility with TV browser (Chrome 47)

    Compatibility with TV browser (Chrome 47)

    Issuehunt badges

    Hi, crafting an application with create-react-app, and installing effector/effector-react, in the main file and importing any effector/effector-react functions, the live preview in dev mode returns the following on Chrome 47:

    Unexpected token {
    

    effector 20.0.0/effector-react 20.0.4

    Thank you


    IssueHunt Summary

    zerobias zerobias has been rewarded.

    Backers (Total: $40.00)

    Submitted pull Requests


    Tips


    IssueHunt has been backed by the following sponsors. Become a sponsor

    :gift: Rewarded on Issuehunt compatibility 
    opened by johneisenheim 13
  • `effector/babel-plugin` plugin doesn't process `factories` field

    `effector/babel-plugin` plugin doesn't process `factories` field

    What is the current behavior: If you add the factories field in the effector/babel-plugin configuration and specify the actual path of the factory that is imported into the model files, then the sid for units is specified without additionally specifying the sid of the factory.

    Please provide the steps to reproduce and if possible a minimal demo of the problem via https://share.effector.dev, https://codesandbox.io or similar: https://stackblitz.com/edit/effector-react-1eg5yl?file=src%2Fmodel.ts

    What is the expected behavior: The factories field is handled correctly and the sid of the units created by the factory is different.

    Which versions of effector packages, and which browser and OS are affected by this issue? Did this work in previous versions of effector?: OS: any Browser: any

    Did this work in previous versions of effector?

    I don't know.

    question 
    opened by rushelex 11
  • Usage with v-model? (Vue)

    Usage with v-model? (Vue)

    Hello, is there a way to bind a store on v-model (read/write)?

    <input v-model="search">
    
    const $search= createStore('hey')
    const search= ???
    

    Thanks!

    documentation effector-vue 
    opened by maximelebreton 11
  • Standartize `fx.finally` like in `allSettled`

    Standartize `fx.finally` like in `allSettled`

    Proposal

    Add field value for .finally when status is "fail". New field should be an alias for error.

    1. be consistent with the allSettled
    2. have the same shape as with status "done"

    Do not remove error property

    Use case

    1. Simple destructuring
    const result = fx.finally.map(({ value }) => value)
    // doesn't matter "fail" or "done", just give me a value
    

    compare with:

    const result = fx.finally.map((data) => data.status === 'fail' ? data.error : data.value )
    
    RFC 
    opened by sergeysova 10
  • How to properly mock store

    How to properly mock store

    Hello everyone.

    I'm trying to get the best possible way to mock a store in unit tests. I came up with a simple way to just mock getState method but I think there is a better solution floating around.

    I have a simple CounterComponent:

    import counter from 'stores/counter';
    import { useStore } from 'effector-react';
    
    export default function CounterComponent() {
      const counter = useStore(counter);
    
      return (
        <h1>Current counter: {counter}</h1>
      );
    }
    

    And I want to unit test it and check that it's displaying value from the store but I don't want to test the store itself. So I came up with this:

    import counter from 'stores/counter'
    
    jest.mock('stores/counter', () => {
      const actualObject = jest.requireActual('stores/counter');
    
      return {
        ...actualObject,
        getState: jest.fn()
      }
    })
    
    describe('CounterComponent Unit', () => {
      it('should display counter from counter store', () => {
        counter.getState.mockReturnValueOnce(0)
    
        // just to make it shorter I skipped rendering and finding part of the test,
        // imagine that this is the result of testing-library or any other library
        const textContent = 0
    
        expect(textContent).toBe(0)
      });
    });
    

    How do you unit test in this case? Any suggestions?

    question 
    opened by pbelyaev 10
  • Allow to pass `domain` to `attach` without parent effect

    Allow to pass `domain` to `attach` without parent effect

    It is useful only when attach doesn't have a parent domain.

    Proposal

    Propose to add domain for the attach operator when parameters source and effect appeared.

    const domain = createDomain()
    const $store = createStore(0)
    
    const fx = attach({
      domain,
      source: $store,
      async effect(source, params: void) {
        // logic
      },
    })
    

    Use case

    We need to cover cases when created effect needs to be handled by the effect's hook .onCreateEffect, but in previous versions, there was no ability to do this.

    Related #763

    RFC 
    opened by sergeysova 0
  • Stabilize new documentation

    Stabilize new documentation

    • [ ] Algolia
      • [ ] Reconfigure crawler
      • [ ] Reset DocSearch to update indexes
      • [ ] Reconfigure workflow from beta API key to stable
    • [ ] Rename beta directory
    • [ ] Change editLink.pattern to the main docs
    • [ ] Change on.push.paths in the workflow and working directory in the build steps
    documentation 
    opened by sergeysova 0
  • [effector-react/scope]: useUnit Bug

    [effector-react/scope]: useUnit Bug

    What is the current behavior: Units used with useUnit from effector-react/scope in next.js project is most likely has batching in the wrong way, and maybe for this reason when navigating when scope changes, in a certain case, these units lose synchronization and are no longer available for use. In my case I have a simple toggler factory, so it is broken when you navigate to the same page.

    DEMO LINK

    Please provide the steps to reproduce and if possible a minimal demo of the problem via https://share.effector.dev, https://codesandbox.io or similar

    1. Open demo link
    2. Click to hamburger button to see that drawer that use the $isOpen, toggle, ... state from toggler instance works correctly
    3. Click to GO_TO_THIS_PAGE_AGAIN link, and try to open hamburger menu again - it's broken now

    Any another cases of navigation don't produce this issue:

    1. Click to Go to another page link and repeat step 2 to see that all still works.
    2. From page from step 3 you can go back to home page in 2 ways - 1st - with router events, 2nd - directly with link - all works fine as expected

    What is the expected behavior: I expected that useUnit have the same behavior as useStore/useEvent. Because, if we will use it as a replacement for useUnit, the issue is gone. Demo with useStore/useEvent without described bug: LINK HERE

    Which versions of effector packages, and which browser and OS are affected by this issue? Did this work in previous versions of effector?: All latest versions

    bug needs triage 
    opened by 7iomka 1
  • Make `shape` instead of `store` parameter in useStoreMap

    Make `shape` instead of `store` parameter in useStoreMap

    Proposal

    const data = useStoreMap({
      shape: [$a, $b], // ! now: `store: combine([$a, $b])`
      keys: deps,
      fn: ([a, b], deps) => ...
    });
    

    https://t.me/effector_ru/279338

    Use case

    sometimes you need more than one store in useStoreMap hook

    RFC 
    opened by xaota 1
  • generic typeguard do not work as filter

    generic typeguard do not work as filter

    What is the current behavior: https://tsplay.dev/wXq5JN

    import {sample, createEvent, createEffect, createStore} from "effector";
    
    type Doggy<D> = {
        readonly _tag: 'Dog';
        readonly barkingTime: D;
    }
    type Catty<C> = {
        readonly _tag: 'Cat';
        readonly milkSounds: C;
    }
    type Pet<D, C> = Doggy<D> | Catty<C>;
    
    
    const SmallCat: Catty<string> = {
        _tag: 'Cat',
        milkSounds: 'mew'
    }
    
    const whenFeedCat = createEvent<string>();
    const $activePet = createStore<Pet<number, string>>(SmallCat);
    const printMilkFx = createEffect(({milk, time}: {
        milk: string,
        time: string
    }) => {
        console.log(`Feed at ${time} when milk is ${milk}`);
    });
    
    
    
    sample({
        clock: whenFeedCat,
        source: $activePet,
        filter: isCat,
        fn: (cat, time) => ({milk: cat.milkSounds, time}), // TS error
        target: printMilkFx
    })
    
    sample({
        clock: whenFeedCat,
        source: $activePet,
        filter: (pet: Pet<number, string>) => isCat(pet),
        fn: (cat, time) => ({milk: cat.milkSounds, time}), // TS error
        target: printMilkFx
    })
    
    sample({
        clock: whenFeedCat,
        source: $activePet,
        filter: pet => isCat(pet),
        fn: (cat, time) => ({milk: cat.milkSounds, time}), // TS error
        target: printMilkFx
    })
    
    function isCat<A>(pet: Pet<any, A>): pet is Catty<A> {
        return pet._tag === 'Cat';
    }
    
    

    What is the expected behavior: Proper types

    Which versions of effector packages, and which browser and OS are affected by this issue? Did this work in previous versions of effector?: latest

    bug typings needs triage 
    opened by Lonli-Lokli 1
  • `fromObservable` do not work with BehaviorSubject

    `fromObservable` do not work with BehaviorSubject

    What is the current behavior: fromObservable do not work (clocks) with BehaviorSubject from rxjs

    import { BehaviorSubject, interval } from 'rxjs';
    import { fromObservable, sample } from 'effector';
    
    //emit value in sequence every 1 second
    const source = new BehaviorSubject(1000); // DO NOT WORK
    // const source = interval(1000); // WORKS
    
    const output = sample({
      clock: fromObservable<number>(source),
    });
    
    //output: nothing
    output.watch(console.log);
    

    What is the expected behavior:

    • It should start calculation when used directly as a clock
    • It should update store with shortcut restore(fromObservable(rxjs$), {defaultValue})

    Which versions of effector packages, and which browser and OS are affected by this issue? Did this work in previous versions of effector?: Windows 11, effector 22.4.0

    bug needs triage 
    opened by Lonli-Lokli 0
  • [email protected](Dec 13, 2022)

    • 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!

    Source code(tar.gz)
    Source code(zip)
  • [email protected](Nov 5, 2022)

    • 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 reset store to default value (PR #797)

    Before $store.reinit:

    const $formValues = createStore<FormValues | null>(null);
    
    sample({
     clock: [timeoutOut, buttonClicked, meteorHit],
     target: [
       saveAllStuffFx,
     ]
    })
    
    // here we would need to duplicate the same clocks 👎 
    $formValues.reset([timeoutOut, buttonClicked, meteorHit])
    

    With $store.reinit:

    const $formValues = createStore<FormValues | null>(null);
    
    sample({
     clock: [timeoutOut, buttonClicked, meteorHit],
     target: [
       saveAllStuffFx,
       // reset $formValues back to null due to one of the clock reasons
       $formValues.reinit,
       // no need to duplicate clocks list 👍 
     ]
    })
    
    • 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)
    Source code(tar.gz)
    Source code(zip)
  • [email protected](Oct 24, 2022)

  • [email protected](Oct 4, 2022)

  • [email protected](Sep 28, 2022)

  • [email protected](Sep 21, 2022)

  • [email protected](Sep 19, 2022)

    • 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
    Source code(tar.gz)
    Source code(zip)
  • [email protected](Sep 16, 2022)

  • [email protected](Sep 16, 2022)

  • [email protected](Sep 16, 2022)

    What's New

    • 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

    New Contributors

    • @usmanyunusov made their first contribution in https://github.com/effector/effector/pull/782
    Source code(tar.gz)
    Source code(zip)
  • [email protected](Sep 16, 2022)

    What's Changed

    • 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 all hooks 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)

    New Contributors

    • @sagdeev made their first contribution in https://github.com/effector/effector/pull/776
    • @rachaeldawn made their first contribution in https://github.com/effector/effector/pull/759
    Source code(tar.gz)
    Source code(zip)
  • [email protected](Aug 31, 2022)

  • [email protected](Aug 31, 2022)

  • [email protected](Aug 31, 2022)

  • [email protected](Aug 1, 2022)

  • [email protected](Aug 1, 2022)

  • [email protected](Jul 27, 2022)

  • [email protected](Jul 13, 2022)

    What's Changed

    • 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 {createEvent, createStore, fork} from 'effector'
    import {useUnit, 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)

    Documentation Updates

    • Fix example of Gate usage in documentation by @7iomka in https://github.com/effector/effector/pull/669
    • Rewrite API section in the usage with react by @sergeysova in https://github.com/effector/effector/pull/682
    • docs: useUnit basic usage by @AlexandrHoroshih in https://github.com/effector/effector/pull/738

    New Contributors

    • @nonzzz made their first contribution in https://github.com/effector/effector/pull/663
    • @7iomka made their first contribution in https://github.com/effector/effector/pull/669
    • @yialo made their first contribution in https://github.com/effector/effector/pull/671
    • @Drevoed made their first contribution in https://github.com/effector/effector/pull/685
    • @lud made their first contribution in https://github.com/effector/effector/pull/715
    • @xxxxue made their first contribution in https://github.com/effector/effector/pull/716
    • @anatolykopyl made their first contribution in https://github.com/effector/effector/pull/724
    • @ainursharaev made their first contribution in https://github.com/effector/effector/pull/730

    Full Changelog: https://github.com/effector/effector/compare/[email protected]@22.1.0

    Source code(tar.gz)
    Source code(zip)
  • [email protected](Apr 15, 2022)

    Features

    • Added documentation for utility types https://github.com/effector/effector/commit/55d300d762c9104e22e138aed28e27c44a51cbf8
    • Added new utility method createWatch https://github.com/effector/effector/pull/646

    New Contributors

    • @VadimFilimonov made their first contribution in https://github.com/effector/effector/pull/653
    • @cqh963852 made their first contribution in https://github.com/effector/effector/pull/657
    • @sagdeev made their first contribution in https://github.com/effector/effector/pull/661

    Full Changelog: https://github.com/effector/effector/compare/[email protected]@22.3.0

    Source code(tar.gz)
    Source code(zip)
  • [email protected](Apr 6, 2022)

  • [email protected](Apr 5, 2022)

    Features

    Added support for classList in h() and spec() #638

    CSS classes can be merged and applied via multiple spec() calls:

    h('div', {
      attr: { class: "basic" },
      classList: ["another"],
      fn() {
        spec({ classList: { first: true, second: false } })
        spec({ classList: ['second', 'third'] })
      },
    })
    

    Result will be:

    <div class="basic another first second third"></div>
    
    Source code(tar.gz)
    Source code(zip)
  • [email protected](Feb 1, 2022)

    • 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)
    Source code(tar.gz)
    Source code(zip)
  • [email protected](Jan 7, 2022)

  • [email protected](Dec 8, 2021)

  • [email protected](Oct 8, 2021)

    • Allow to use effector/babel-plugin in patronum/macro https://github.com/effector/effector/commit/68dffae660eea209de17e6d88b72edb7c82b87de
    Source code(tar.gz)
    Source code(zip)
  • [email protected](Sep 10, 2021)

  • [email protected](Sep 4, 2021)

    • 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.

    Source code(tar.gz)
    Source code(zip)
Owner
effector ☄️
Effector is an effective multi-store state manager for Javascript apps
effector ☄️
Prefetch and sync state to client with one line of code, out-of-the-box

vue3-SSR-starter Prefetch and sync state to client with one line of code, out-of-the-box Features vue3 SSR vue-router we don't need vuex anymore one l

周子贤 36 Aug 28, 2022
Next version of massCode [WIP]. A free and open source code snippets manager for developers

massCode next Built with Electron, Vue 3 & Ace Editor. Inspired by applications like SnippetsLab and Quiver. ☝️ massCode is currently in development,

null 4.3k Jan 5, 2023
Code snippets manager for developers. PWA.

Snippets Ninja About Snippets.Ninja is a progressive web application for code snippet management. Offline first. Open Source. App uses IndexedDB for l

Magalyas Dmitry 71 Dec 19, 2022
Create a performant distributed context state by synergyzing atomar context pieces and composing reusable state logic.

Synergies Create a performant distributed context state by synergyzing atomar context pieces and composing reusable state logic. synergies is a tiny (

Lukas Bach 8 Nov 8, 2022
The state manager ☄️

☄️ effector The state manager Table of Contents Introduction Effector follows five basic principles: Installation Documentation Packages Articles Comm

effector ☄️ 4.1k Jan 9, 2023
Whoosh - minimalistic React state manager

Whoosh - minimalistic React state manager Whoosh is a React state manager which entire API consists of exactly one function - createShared(). TL;DR ve

Alexander Blk 9 Nov 7, 2022
A devtool improve your pakage manager use experience no more care about what package manager is this repo use; one line, try all.

pi A devtool improve your pakage manager use experience no more care about what package manager is this repo use; one line, try all. Stargazers over t

tick 11 Nov 1, 2022
Meogic-tab-manager is an extensible, headless JavaScript tab manager framework.

MeogicTabManager English document MeogicTabManager是一个有可拓展性的、headless的JavaScript标签页管理框架。 MeogicTabManager旨在提供可自由组装页面框架、自定义页面组件、甚至覆盖框架自带事件响应的开发体验。 Meogi

meogic-tech 5 Oct 8, 2022
A Higher Order Component using react-redux to keep form state in a Redux store

redux-form You build great forms, but do you know HOW users use your forms? Find out with Form Nerd! Professional analytics from the creator of Redux

Redux Form 12.6k Jan 3, 2023
Recoil is an experimental state management library for React apps. It provides several capabilities that are difficult to achieve with React alone, while being compatible with the newest features of React.

Recoil · Recoil is an experimental set of utilities for state management with React. Please see the website: https://recoiljs.org Installation The Rec

Facebook Experimental 18.2k Jan 8, 2023
🐻 Bear necessities for state management in React

A small, fast and scaleable bearbones state-management solution. Has a comfy api based on hooks, isn't boilerplatey or opinionated, but still just eno

Poimandres 25.5k Jan 9, 2023
🏁 High performance subscription-based form state management for React

You build great forms, but do you know HOW users use your forms? Find out with Form Nerd! Professional analytics from the creator of React Final Form.

Final Form 7.2k Jan 7, 2023
🗃️ Centralized State Management for Vue.js.

Vuex ?? HEADS UP! You're currently looking at Vuex 3 branch. If you're looking for Vuex 4, please check out 4.0 branch. Vuex is a state management pat

vuejs 27.9k Dec 30, 2022
Simple, scalable state management.

MobX Simple, scalable state management. Documentation for older unsupported V4/V5 can be found here, but be sure to read about current documentation f

MobX 26k Jan 3, 2023
State management that tailored for react, it is simple, predictable, progressive and efficient.

English | 简体中文 ⚡️ State management that tailored for react, it is simple, predictable, progressive and efficient. ?? Introduction Concent is an amazin

cencentjs 1.1k Dec 28, 2022
Create the next immutable state by mutating the current one

Immer Create the next immutable state tree by simply modifying the current tree Winner of the "Breakthrough of the year" React open source award and "

immer 24.2k Dec 31, 2022
Prefetch and sync state to client with one line of code, out-of-the-box

vue3-SSR-starter Prefetch and sync state to client with one line of code, out-of-the-box Features vue3 SSR vue-router we don't need vuex anymore one l

周子贤 36 Aug 28, 2022
A state management library for React, heavily inspired by vuex

Vuex - But for React! ⚛ If you know vuex, you know it's as close as we get to a perfect state management library. What if we could do this in the reac

Dana Janoskova 103 Sep 8, 2022
Real state property listing app using next.js , chakra.ui, SCSS

This is a Next.js project bootstrapped with create-next-app. Getting Started First, run the development server: npm run dev # or yarn dev Open http://

null 1 Dec 19, 2021
experimental project for babel-plugin-mutable-react-state

Goalist Mutable React Example This example is an attempt to work with babel-plugin-mutable-react-state on a simpler project to see how complicated wou

Reaper 1 Jun 7, 2022