Migrating existing Redux applications

Since kea is just redux, it is very easy to connect it to an existing redux application.

Reading external data

You may pull in data from any part of the Redux tree with the Kea. For this you will use either the @connect({ props: [] }) helper or the connect: { props: [] } option in the @kea({}) function.

Instead of passing a kea logic store to props you just pass a selector. Like so:

import { connect } from 'kea'

import someLogic from './some-logic'

const railsContext = (state) => state.rails

@connect({
  props: [
    someLogic, [
      'prop1',
      'prop2'
    ],
    railsContext, [
      'i18nLocale',
      'currentUserId'
    ],
    (state) => state.form.myForm, [
      '* as myForm'
    ]
  ]
})
export default const MyComponent extends Component {
  render () {
    const { prop1, prop2, i18nLocale, currentUserId, myForm } = this.props
    // ...
  }
}

Using external actions

Kea always adds dispatch as one of the props to your app, so you can easily call actions that are defined elsewhere.

import React, { Component } from 'react'
import { kea } from 'kea'
import { push } from 'react-router-redux'

import doSomething from './actions/do-something'

// just to get the dispatch
@kea({})
export default const MyComponent extends Component {
  handleButton = () => {
    const { dispatch } = this.props

    // call the action
    dispatch(doSomething())

    // ask redux-router to take us home
    dispatch(push('/home'))
  }

  render () {
    return (
      <div>
        <button onClick={this.handleButton}>
          Do something
        </button>
      </div>
    )
  }
}

You may listen to other actions and either have them influence your reducers or run a saga when they happen. Just replace actions.something with MY_TYPE_CONSTANT, like so:

import React, { Component } from 'react'
import { kea } from 'kea'
import { LOCATION_CHANGE } from 'react-router-redux'

import { SOME_ACTION } from './actions'

@kea({
  actions: () => ({
    doit: true
  }),

  reducer: ({ actions }) => ({
    myValue: [false, PropTypes.bool, {
      [SOME_ACTION]: () => false,
      [actions.doit]: () => true
    }]
  }),

  takeEvery: ({ workers }) => ({
    [LOCATION_CHANGE]: workers.urlToState
  }),

  workers: {
    * urlToStateWorker (action) {
      const { search, pathname } = action.payload
      // ...
    }
  }
})
export default const MyComponent extends Component {
  // ...
}

Using Kea actions and selectors elsewhere

If the redux-only part of your app needs access to some props or actions from kea logic stores, you can import them like so:

// my-logic.js
export default kea({
  actions: () => ({
    addOne: true
  }),
  reducers: ({ actions }) => ({
    myNumber: [0, PropTypes.number, {
      [actions.addOne]: (state) => state + 1
    }]
  }),
  selectors: ({ selectors }) => ({
    myNumberDouble: [
      () => [selectors.myNumber],
      (myNumber) => myNumber * 2,
      PropTypes.number
    ]
  })
})

// component
import TodoList from '../components/TodoList'
import { toggleTodo } from '../actions'

import myLogic from './my-logic'

const mapStateToProps = state => {
  return {
    todos: state => state.todos,
    myNumber: myLogic.selectors.myNumber,
    myNumberDouble: myLogic.selectors.myNumberDouble,
  }
}

const mapDispatchToProps = dispatch => {
  return {
    onTodoClick: id => dispatch(toggleTodo(id)),
    onAddOneClick: () => dispatch(myLogic.actions.addOne())
  }
}

const ConnectedTodoList = connect(
  mapStateToProps,
  mapDispatchToProps
)(TodoList)

export default ConnectedTodoList

The API docs describe what is available to import.

Next steps

That's it for the guide!

Check out the example applications or read the API docs.