This documentation is for the old Kea 0.28. To see the latest docs, click here!

kea(options)(Component)

Wrap a kea logic store around a React component.

The React component will receive all of the logic store's selectors in this.props and all actions under this.actions.

import React, { Component } from 'react'
import { kea } from 'kea'

import otherLogic from './other-logic'

@kea({
  key: (props) => props.id,
  path: (key) => ['scenes', 'something', key],

  actions: () => ({
    someAction: (id) => ({ id })
  }),

  reducers: ({ actions }) => ({
    myValue: [0, PropTypes.number, {
      [actions.someAction]: (state, payload): payload.id
    }]
  }),

  selectors: ({ selectors }) => ({
    combinedValue: [
      () => [
        selectors.myValue,
        otherLogic.selectors.otherValue,
        (state, props) => props.id
      ],
      (myValue, otherValue, id) => myValue + otherValue + id,
      PropTypes.number
    ]
  })

  // other options, see the api docs for kea(options):
  // - connect, constants, start, stop, takeEvery, takeLatest, workers, sagas
})
export default class MyComponent extends Component {
  render () {
    const { myValue, combinedValue } = this.props
    const { someAction } = this.actions

    return (
      <div>
        <div>Combined props and reducer in a selector: {combinedValue}</div>
        <button onClick={() => someAction(12)}>{myValue}</button>
      </div>
    )
  }
}

It's up to you if you wish to use decorators or not:

import React, { Component } from 'react'
import { kea } from 'kea'

// with decorators
@kea({ /* options */ })
export default class MyComponent extends Component {
  // ...
}

// without decorators
class MyComponent extends Component {
  // ...
}
export default kea({ /* options */ })(MyComponent)

See the installation guide for details.

Stateless functional components

You may also use kea with stateless functional components. The syntax can get quite lispy with all the brackets, but it works:

export default kea({
  actions: () => ({
    action1: true,
    action2: false
  }),
  reducers: () => ({
    prop1: [...],
    prop2: [...]
  }),
  connect: {
    actions: [
      otherLogic, [
        'importedAction1'
      ]
    ],
    props: [
      otherLogic, [
        'importedProp1'
      ]
    ]
  },
  // ... other kea options
})(({
  prop1, prop2, importedProp1,
  // actions are always also passed in a prop called 'actions'
  actions: { action1, action2, importedAction1 }
}) => (
  <div>
    <button onClick={action1}>{prop1}</button>
  </div>
))

Options

Wrapped logic stores accept all the same options as regular logic stores. See the documentation for kea(options) for more details.

These options are different:

key: (props) => 'key'

If you wish, you may define a key that distinguishes instances of the component.

Read the dynamic counter guide guide to learn about in more depth!

key: (props) => props.id

path: (key) => []

The path takes the key as an argument if you wish to define the location in redux for the component instance

path: (key) => ['scenes', 'homepage', 'sliders', key]

selectors: ({ path, constants, actions, selectors }) => ({})

The selectors have an additional feature with wrapped logic stores. You can access the props passed to your component like so:

selectors: ({ selectors }) => ({
  combinedValue: [
    () => [
      // standard selector for myValue
      selectors.myValue,

      // use a selector from a different logic store without conencting the prop
      otherLogic.selectors.otherValue,

      // props are passed as the second argument to input selectors
      (state, props) => props.id
    ],
    (myValue, otherValue, id) => myValue + otherValue + id,
    PropTypes.number
  ]
})