effector

Business logic with ease ☄️

MIT License

Downloads
370.3K
Stars
4.5K
Committers
151
effector - effector 20.3.1

Published by zerobias about 5 years ago

  • Fix edge case when clearNode been called on store belonged to certain domain led to the removal of the entire domain
effector - effector-react 20.4.0

Published by zerobias about 5 years ago

  • Add support for keys field in useList. By default, useList rerenders only when some of its items were changed.
    However, 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 - effector 20.3.0

Published by zerobias about 5 years ago

  • Add shortName to domains
import {createDomain} from 'effector'
const domain = createDomain('feature')
console.log(domain.shortName)
// => feature

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)
// => {stores: Set{storeB}, events: Set{eventA}, domains: Set, effects: Set}

try it

effector - effector-vue 20.2.0

Published by goodmind about 5 years ago

  • Add support for object shape
const counter = createStore(0)

new Vue({
  effector: {
    counter, // would create `counter` in template
  }
})
effector - @effector/[email protected]

Published by sergeysova about 5 years ago

Add .sid — stable hash identifier for events, effects, stores and domains, preserved between environments, to handle client-server interaction within the same codebase

See example project

effector - effector 20.2.0

Published by zerobias about 5 years ago

  • 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.
/* common.js */

import {createEffect} from 'effector'

export const getUser = createEffect({sid: 'GET /user'})
console.log(getUsers.sid)
// => GET /user

/* worker.js */

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

/* client.js */

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 effect = createEffect({handler})

effect()
  • Fix bug with cannot read property .toString of undefined error during store initialization
effector - effector-react 20.3.0

Published by zerobias about 5 years ago

  • Add support for react hooks in createComponent
effector - effector 20.1.2, effector-react 20.2.2, effector-vue 20.1.2

Published by zerobias about 5 years ago

effector

  • Allow typescript to refine type of payload if event.filter({fn}) got a predicate function as a callback PR
import {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}) // Event<string>
const num = event.filter({fn: isNumber}) // Event<number>

str.watch(value => value.slice()) // OK now
num.watch(value => value.toFixed(2)) // OK now
  • Allow typescript to refine type with is methods PR
import {is} from 'effector'

//result has type Event<any> | void
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-react, effector-vue

  • 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 - effector 20.1.1, effector-react 20.2.1, effector-vue 20.1.1

Published by zerobias about 5 years ago

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 - effector-react 20.2.0

Published by zerobias about 5 years ago

  • Add effector-react/compat module to use with Smart TV (Chrome 47) apps without babel
effector - effector 20.1.0

Published by zerobias about 5 years ago

  • 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 - effector-react 20.1.1

Published by zerobias over 5 years ago

  • 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 = () => {
  // note that we don't need keys here any more
  const users = useList(list, ({name}, i) => (
    <div>
      {i}) {name}
    </div>
  ))
  return <div>{users}</div>
}

ReactDOM.render(<List />, document.getElementById('root'))

try it

effector - effector-react 20.0.3

Published by zerobias over 5 years ago

  • Allow as const typescript assertion for useStoreMap keys. It helps us to infer type for fn arguments
import React from 'react'
import {createStore} from 'effector'
import {useStoreMap} from 'effector-react'

type User = {
  username: string
  email: string
  bio: string
}

const users = createStore<User[]>([
  {
    username: 'alice',
    email: '[email protected]',
    bio: '. . .',
  },
  {
    username: 'bob',
    email: '[email protected]',
    bio: '~/ - /~',
  },
  {
    username: 'carol',
    email: '[email protected]',
    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 {createStore} from 'effector'
import {useStoreMap} from 'effector-react'

type User = {
  username: string
  email: string
  bio: string
}

const users = createStore<User[]>([
  {
    username: 'alice',
    email: '[email protected]',
    bio: '. . .',
  },
  {
    username: 'bob',
    email: '[email protected]',
    bio: '~/ - /~',
  },
  {
    username: 'carol',
    email: '[email protected]',
    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 - effector-react 20.0.2

Published by zerobias over 5 years ago

  • Fix bug with additional rerender in case of useStore argument change
effector - effector-react 20.0.1

Published by zerobias over 5 years ago

  • Fix flow typings for useStoreMap
effector - effector 20.0.0

Published by zerobias over 5 years ago

  • 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)
// => merged event triggered: 1
bar(2)
// => merged event triggered: 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'})
// => [bob]: Hello
message({user: 'alice', text: 'Hi bob'})
// => [alice]: Hi bob

/* default case, triggered if no one condition met */
const {__: guest} = messageByAuthor
guest.watch(({text}) => {
  console.log('[guest]: ', text)
})
message({user: 'unregistered', text: 'hi'})
// => [guest]: 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()
// => intermediate step
// => target watcher
clearNode(target)
source() // ~ no reaction ~

try it

  • Fix promise warning for effects

  • Add effect.finally

import {createEffect} from 'effector'
const fetchApi = createEffect({
  handler: n =>
    new Promise(resolve => {
      setTimeout(resolve, n, `${n} ms`)
    }),
})
fetchApi.finally.watch(response => {
  console.log(response)
})

await fetchApi(10)
// => {status: 'done', result: '10 ms', params: 10}

// or

// => {status: 'fail', error: Error, params: 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.* reexports
effector - effector-react 20.0.0

Published by zerobias over 5 years ago

  • Remove unstable_createStoreProvider
effector - effector-vue 20.0.0

Published by zerobias over 5 years ago

Vue adapter for effector 20

effector - effector-react 19.1.2

Published by zerobias over 5 years ago

  • 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: user$,
    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 - effector 19.1.0

Published by zerobias over 5 years ago

  • Add support for event.filter with common predicate functions
import {createEvent} from 'effector'

const event = createEvent()

// that event will be triggered only when fn returns true
const filtered = event.filter({
  fn: x => x > 0,
})

filtered.watch(x => console.log('x =', x))

event(-2) // nothing happens
event(2) // => x = 2

try it

Package Rankings
Top 1.08% on Npmjs.org
Top 14.96% on Deno.land
Badges
Extracted from project README
Tested with browserstack