API Reference

feeble API

feeble(options)

Create a feeble app.

  • options: Object - A list of options to pass to the app, currently supported options are:
    • callApi: Function - A function interact wiht server, if this option is presented, Feeble will add a api middleware to Redux store, see more details for api middleware.

feeble.model(options)

Create a model.

  • options: Object - A list of options to pass to the model, currently supported options are:
    • namespace: String - Namespace of the model, this is required. Namespace can be nested by a double colon ::.
    • state: any - Initial state of the model.

connect(mapStateToProps, mapDispatchToProps, mergeProps, options)

Same as react-redux's connect.

app API

app.model(...args)

  • args: Array<any> - An array of models.

Attach one or multiple models to the app. The app's initial state tree will generate from attached model's namespace and initial state. And model's reducer will mount to the specify node by model's namespace.

Example

const app = feeble()

const count = feeble.model({
  namespace: 'count',
  state: 0,
})

const todoA = feeble.model({
  namespace: 'todo::a',
  state: [ 'bar' ],
})

const todoB = feeble.model({
  namespace: 'todo::b',
  state: [ 'foo' ],
})

app.model(count, todoA, todoB)

Above example will generate following state tree:

{
  count: 0,
  todo: {
    a: [ 'bar' ],
    b: [ 'foo' ],
  },
}

And count's reducer will mount to count, todoA's reducer will mount to todo.a, todoB's reducer will mount to todo.b. Namespace is a good way to split you large application to small modules.

app.middleware(...args)

  • args: Array<any> - An array of middlewares

Apply Redux middlewares to your app.

app.mount(component)

  • component: Component - A React component instance.

Mount a component the you app, it's useful when you want testing your container components.

Example

import test from 'ava'
import app from './app' // <== yor app
import { mount } from 'enzyme'
import React from 'react'
import Counter from 'containers/Counter' // <== Container component you want test

test('todo', t => {
 const wrapper = mount(app.mount(<Counter />))

 wrapper.find('#increment').simulate('click')

 t.is(app.store.getState().count, 1)
})

app.tree()

Access your app's root React instance.

app.store

Access Redux store.

model API

model.action(name, [fn], [fn])

Create a action creator.

  • name: String: Name of the action creator, the name should be validate JavaScript function name, because action creator will be a method of model.
  • fn: Function: Transform multiple arguments as the payload. If you omit this param, the first argument pass to action creator will be the payload.
  • fn: Function: Transform multiple arguments as the meta.

Example

const foo = feeble.model({
  namespace: 'foo'
})

// create a "simple" method on "foo"
foo.action('simple')
// produce "{ type: 'todo::simple', payload: 'blah' }"
foo.simple('blah')

// create a "better" method on "foo"
foo.action('better', str => str + str)
// produce "{ type: 'todo::better', payload: 'blah blah' }"
foo.better('blah')

// create a "best" method on "foo"
foo.action('best', str => str + str, str => str.toUpperCase())
// produce "{ type: 'todo::best', payload: 'blah blah', meta: 'BLAH' }"
foo.best('blah')

model.apiAction(name, fn, [fn])

Create a API call action creator.

If set callApi option to app, model will expose apiAction to allow you create API call action creator.

  • name: String - Name of the action creator.
  • fn: Function: Transform multiple arguments as the api request.
  • fn: Function: Transform multiple arguments as the meta.

Example

const todo = feeble.model({
  namespace: 'todo',
  state: [],
})

todo.apiAction('create', name => ({
  method: 'post',
  endpoint: '/todos',
  body: { name },
}))

When you call todo.create('Workout') will produce following action:

{
  types: ['todo::create_request', 'todo::create_success', 'todo::create_error'],
  [CALL_API]: {
    method: 'post',
    endpoint: '/todos',
    body: { name },
  },
}

When api middleware find a [CALL_API] property in the action, it will dispatch a request action and pass the "CALL_API" object to your "callApi" function, here is the request action:

{
  type: 'todo::create_request',
  payload: {
    method: 'post',
    endpoint: '/todos',
    body: { name },
  }
}

Then, api api middleware calls your "callApi" function, after "callApi" returns promise resolved, following action will be dispatched:

{
  type: 'todo::create_success',
  payload: {
    name: 'Workout'
  }
}

If "callApi" rejects, a error action will be dispatched:

{
  type: 'todo::create_error',
  payload: "errors from server",
  error: true,
}

model.reducer(fn)

Create reducer.

  • fn: Function - A function takes a on param which register action to the reducer.

Example

count.reducer(on => {
  on(todo.increment, (state, payload) => state + payload)
  on(todo.decrement, (state, payload) => state + payload)
})

model.selector(name, ...fns, fn, options)

  • name: Function - Name of the selector, access the selector by calling model.select(name) later.
  • fns: Array<Function> - Input selectors.
  • fn: Function - Result function.
  • options: Object - A list of options, currently supported options are:
    • structured: Boolean - Create a structured selector if true.

model.select(name, ...args)

Access selectors.

  • name: Function - Name of the selector.
  • args: Array<any> - Arguments pass to the selector.

model.effect(fn)

Create effect.

  • fn: Function - A generator function.

Example

model.effect(function* {
  yield* takeEvery(count.increment, function* ({ payload }) {
    yield call(localStorage.setItem, 'count', payload)
  })
})

Using fork to create multiple effects:

model.effect(function* {
  yield [
    fork(effect1),
    fork(effect2),
  ]
})

model.addReducer(fn)

Add a exists reducer to model. This is useful when you work with third party libraries or you legacy codes.

  • fn: Function - A normal Redux reducer.

model.getState()

Get current model state.

effects API

All api exposed from feeble/effects are all expoted from redux-saga/effects directly, except take, takem, actionChannel. These three functions are wrapped by feeble to make them accept feeble's action creator as pattern.

effects helper API

All api exposed from feeble/effects/helper are all expoted from redux-saga directly, except tekEvery and takeLatest. These two functions are wrapped by feeble to make them accept feeble's action creator as pattern.