Nope, prefer mopeds.

    smitty

    2.0.3 • Public • Published

    smitty
    smitty

    Tiny flux implementation built on mitt

    smitty

    npm version Build Status codecov

    Install

    npm install -S smitty

    Basic Usage

    import { createStore } from 'smitty'
     
    // Create a store with initial state
    const initialState = { count: 0 }
    const store = createStore(initialState)
     
    store.createActions({
      add: 'count/ADD'
    })
     
    // add a reducer
    store.handleActions({
      [store.actions.add]: (state, e, type) => {
        // increment foos by amount
        return Object.assign({}, state, { count: state.count + e.amount })
      },
      '*': (state, e, type) => {
        // '*' can be used for all kinds of fun stuff
        console.log(e, type)
        if (type === 'count/ADD') {
          //...do something
        }
        return state
      }
    })
     
    store.actions.add({ amount: 5 })
     
    console.log(store.state)  // logs `{ count: 5 }`

    Demos (v2)

    Demos (v1)


    Usage with Preact and React


    API

    createStore(initialState: any)

    Arguments

    initialState: any required: Determines the shape and initial state of your store. Can be of any type that you choose.

    Returns

    Store: Store Store


    Store

    emit: (function)

    arguments

    type: (string | function)

    • [string], type determines which reducers are called.

      const store = createStore(0)
      store.handleActions({
        add: function (state, payload) {
          return state + payload
        }
      })
      console.log(store.state) // logs 0
      store.emit('add', 1)
      console.log(store.state) // logs 1
    • [function] type becomes an action creator that is passed 1 argument

      This is useful to emit multiple actions from a single emit call.

      const store = createStore(0)
      store.handleActions({
        add: function (state, payload) {
          return state + payload
        }
      })
      function asyncAction (emit, state) {
        emit('add', 1)
        console.log(state) // logs 1
        setTimeout(() => {
          emit('add', 1)
          console.log(state) // logs 3
        }, 100)
        emit('add', 1)
        console.log(state) // logs 2
      }
          ```
       

    payload: (any) optional

    payload to pass to your reducer

    const store = createStore({ name: 'Arrow' })
    store.handleActions({
      'update/NAME': function (state, payload) {
        // I really don't care if you return a new state
        // Nobody is judging. Do what your ❤️ tells you.
        // Just be consistent
        return Object.assign({}, state, payload)
      }
    })
    console.log(store.state) // logs { name: 'Arrow' }
    store.emit('update/NAME', { name: 'River' })
    console.log(store.state) // logs { name: 'River' }

    createActions(): (function)

    arguments

    actionMap: (object)

    Object where key is the action creator's name and the value can be of type string or function.

    If the value is a string, an action creator is attached to store.actions as a function that accepts one argument, payload.

    store.createActions({
      add: 'count/ADD'
    })
     
    // The following are functionally equivalent
    store.actions.add(1)
     
    store.emit('count/ADD', 1)
     

    Action creators with a string value can be used as the key in your actionMap in handleActions.

    store.createActions({
      add: 'count/ADD'
    })
     
    // add a reducer
    store.handleActions({
      [store.actions.add]: (state, e, type) => {
        // increment foos by amount
        return Object.assign({}, state, { count: state.count + e.amount })
      }
    })
     
    store.actions.add({ amount: 5 })
     
    console.log(store.state)  // logs `{ count: 5 }`

    If the value is a function, it must be a function that returns an action creator. For async action creators.

    store.createActions({
      add: (amount) => {
        return (store) => {
          setTimeout(() => {
           store.emit('count/ADD', amount)
          }, 16)
        }
      }
    })
     
    store.actions.add(1)
     

    handleActions(): (function)

    arguments

    handlerMap: (object)

    Object with keys that correspond to action types passed to emit

    When an event is emitted and the key matches the type the reducer is invoked with 3 arguments.

    • state: (any) the store's state getter
    • payload (any) the payload that was emitted
    • type (string) the type that was emitted
    const store = createStore({ color: 'blue', hovered: false })
    store.handleActions({
      'merge': function (state, payload) {
        return Object.assign({}, state, payload)
      },
      'overwrite': function (state, payload) {
        return payload
      },
     
      // Could do the same in one
      // If you really miss redux do this and put a switch statement
      '*': function(state, payload, type) {
        return type === 'merge' ? Object.assign({}, state, payload) : payload
      }
    })
    console.log(store.state) // logs { color: 'blue', hovered: false }
    store.emit('merge', { color: 'red' })
    console.log(store.state) // { color: 'red', hovered: false }
    store.emit('overwrite', { color: 'green', hovered: true, highlighted: false })
    console.log(store.state) // { color: 'green', hovered: true, highlighted: false 

    actions: (object)

    Map of all the actions created in store.createActions

    This is convenient so that you do not have to deal with action imports across your app.

    on: (function)

    Convenience shortcut for mitt.on.

    off: (function)

    Convenience shortcut for mitt.off.


    Action Creator Detailed Example

    You can pass a function to emit in order to create an action creator

    running example

    import { createStore } from 'smitty'
     
    // Create a store with initial state
    const initialState = {}
    const store = createStore(initialState)
     
    // add our reducer
    store.handleActions({
      'api/GET_ROOM': (state, { id, res }) => {
        return {
          ...state,
          [id]: {
            ...state[id],
            ...res.data
          }
        }
      }
    })
     
    // create our action creators
    const actions = {
      requestRoom (id) {
        return async (emit, state) => {
          emit('REQUEST_ROOM', { id, res: { data: { id } } })
          const res = await window.fetch(`https://api.mysite.com/${id}`)
          res.data = await res.json()
          emit('REQUEST_ROOM', { id, res })
        }
      }
    }
     
    // When calling emit with a function argument, the function will be called with `emit` and `state` as arguments
    const result = store.emit(actions.requestRoom('1a'))
     
    // Return whatever you like from your action creator
    console.log(result) // logs "Promise {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined}"
     
    // After the fetch call, `REQUEST_ROOM` is fired a second time with our response data
    result.then(() => console.log(store.state)) // logs `{ 1a: { id: '1a', title: 'My Room' }``
     

    Class As Reducer

    Reducers are iterated with for (let type in reducer) {...} with no obj.hasOwnProperty check so this works.

    const store = createStore({ foo: 5 })
     
    class HistoryReducer {
      constructor (initialHistory = []) {
        this.history = createStore(initialHistory)
        this.history.handleActions({
          update: (state, e) => {
            state.push(e)
          }
        })
      }
     
      onUpdate (state, e, type) {
        this.history.emit('update', { state, e, type })
      }
    }
     
    HistoryReducer.prototype['foo/ADD'] = function (state, e, type) {
      state.foo += e.foo
      this.onUpdate(state, e, type)
    }
     
    const historyReducer = new HistoryReducer([])
    store.handleActions(historyReducer)
     
    store.emit('foo/ADD', { foo: 5 })
    console.log(store.state.foo) // logs 10
    store.emit('foo/ADD', { foo: 7 })
    console.log(store.state.foo) // logs 17
    console.log(historyReducer.history.state)
    // logs
    // [
    //   { state: { foo: 10 }, e: { foo: 5 }, type: 'foo/ADD' },
    //   { state: { foo: 17 }, e: { foo: 7 }, type: 'foo/ADD' }
    // ]
     

    Thanks

    Thanks to developit for mitt and the project structure.

    Install

    npm i smitty

    DownloadsWeekly Downloads

    61

    Version

    2.0.3

    License

    MIT

    Last publish

    Collaborators

    • tkh44