Skip to main content

Redux Compatibility

Kea uses redux and reselect under the hood, and it's very easy to connect it to an existing Redux application.

Accessing the Redux store

In listeners or elsewhere, use getContext to get Redux's store object:

import { kea, listeners, getContext } from 'kea'

const railsContext = (state) => state.railsContext // selector

const logic = kea([
listeners({
someAction: () => {
// get the store
const { store } = getContext()
// use a selector to get a state
const { i18nLocale } = railsContext(store.getState())
// dispatch an action in return
store.dispatch({ type: 'REDUX_ACTION' })
},
}),
])

Using Redux actions in reducers and listeners

You can use regular Redux actions in reducers and listeners. Just use their type as a key:

import { kea, actions, reducers, listeners } from 'kea'

import { LOCATION_CHANGE } from 'connected-react-router'

const logic = kea([
actions({
doit: true,
}),

reducers(({ actionTypes }) => ({
myValue: [
false,
{
REDUX_ACTION: () => false, // use redux's action type
[LOCATION_CHANGE]: () => false, // use a type through a variable
doit: () => true, // local action
[actionTypes.doit]: () => true, // local action through a redux type
},
],
})),

listeners({
REDUX_ACTION: (payload) => {
// when the action with the type "REDUX_ACTION" is dispatched
},
[LOCATION_CHANGE]: (payload) => {
// when the location change action is dispatched
},
}),
])

Using non-kea selectors in selectors

You can use regular selectors in your selectors builders:

const localeSelector = (state) => state.railsContext.i18nLocale

const logic = kea([
selectors({
someValue: [
(selectors) => [localeSelector, selectors.name, () => '!'],
(i18nLocale, name, point) => `${name} in ${i18nLocale} is "John"${point}`,
],
}),
])

Converting Redux actions and selectors into Kea actions and values

You may pull in data from any part of the Redux state tree with connect({ values }).

Instead of passing a logic to fetch from, pass a selector:

import { kea, connect } from 'kea'
import someLogic from './someLogic'

const logic = kea([
connect({
values: [
// instead of logic like this
someLogic,
['prop1', 'prop2'],

// pass a selector
(state) => state.rails,
['i18nLocale', 'currentUserId'],

// get everything as 'myForm'
(state) => state.form.myForm,
['* as myForm'],
],
}),

// then use `currentUserId` and others as they were local values
])

Similarly, use an object of action creators and select the ones you need:

import { kea, connect } from 'kea'
import someLogic from './some-logic'

const actionsCreators = {
doSomething: () => ({ type: 'DO_SOMETHING', payload: {} }),
otherAction: ({ id }) => ({ type: 'OTHER_ACTION', payload: { id } }),
}

const logic = kea([
connect({
actions: [
// instead of logic like this
someLogic,
['action1', 'action2'],

// pass an object of action creators
actionsCreators,
['doSomething', 'otherAction'],
],
}),

// they will be automatically binded to dispatch
])

Using Kea actions and selectors elsewhere

If the redux-only part of your app needs access to some values or actions from kea logic stores, use logic.actionCreators and logic.selectors for interoperability. Don't forget to mount the logic first:

const logic = kea([
actions({ addOne: true }),
reducers({ myNumber: [0, { addOne: (state) => state + 1 }] }),
selectors({ myNumberDouble: [(s) => [s.myNumber], (n) => n * 2] }),
])

// The logic must be mounted before you can access its fields
// This is done automatically when a React component is using it.

// If you're using Kea outside React, call logic.mount() manually to have
// access to all the fields below.
const unmount = logic.mount()

// Dispatch an action to add something
logic.actions.addOne()

// Create an action (returns the object { type: 'add one ...', payload: {} })
// and then dispatch it
store.dispatch(logic.actionCreators.addOne())

// Selectors for querying redux (state defaults to getState())
logic.selectors.myNumber(store.getState())
logic.selectors.myNumberDouble(store.getState())

// Shorthand for selectors (implemented as getters)
logic.values.myNumber
logic.values.myNumberDouble

// call unmount when you're done
unmount()

See the docs on logic properties for more details.

Questions & Answers

Ask questions about this page here.