Skip to content
High level abstraction between React and Redux
JavaScript
Branch: master
Clone or download
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
.github Activating Open Collective (#51) Oct 13, 2017
docs
src fix test with undefined action Jun 29, 2019
.babelrc async await mount logic Jun 18, 2019
.eslintrc Update eslint config for 4.x version Jul 27, 2017
.gitignore module code with imports Sep 10, 2017
CHANGELOG.md readme and changelog 1.0.0 links Jun 18, 2019
CONTRIBUTING.md
LICENSE.md empty package Mar 29, 2016
README.md beta version tag Jun 18, 2019
kea-small.jpg
kea.jpg merge into "kea" package, part 1 Dec 5, 2016
kea.svg add svg logo Dec 5, 2016
package.json 1.0.0-rc.2 Jun 25, 2019
rollup.config.js remove inline typeof plugin (issue with apprentus SSR) Apr 23, 2019
yarn.lock [wip] hooks! Jun 11, 2019

README.md

beta version NPM Version minified minified + gzipped Backers on Open Collective Sponsors on Open Collective

NB! Work in progress... and already very usable.

This branch (master) contains work in progress towards version 1.0. The documentation below has not been updated for the latest changes, but reflects the state at the latest pre-1.0 version, 0.28.7. Click here to see that version.

The latest versions 1.0.0-rc.1 is already completely usable, if just a bit sparsely documented.

See this document for a complete overview of what changed in 1.0 including instructions on how to install the latest version. Share your feedback here.

Kea Logo

A kea is two things:

  1. An extremely smart mountain parrot from New Zealand.
  2. An equally smart architecture for frontend webapps, built on top of React and Redux.

Try it out

Open the documentation (AKA demo app) and view its source on GitHub.

In the documentation you will find several examples with source. Check it out!

No, really, check out the docs!

What is Kea?

Kea is a state management library for React. It empowers Redux, making it as easy to use as setState while retaining composability and improving code clarity.

  • 100% Redux: Built on top of redux and reselect.
  • Side effect agnostic: use thunks with redux-thunk, sagas with redux-saga or (soon!) epics with redux-observable.
  • Wrappable: Write logic alongside React components. Easier than setState and perfect for small components.
  • Connectable: Pull in data and actions through ES6+ imports. Built for large and ambitious apps.
  • No boilerplate: Forget mapStateToProps and redundant constants. Only write code that matters!
  • No new concepts: Use actions, reducers and selectors. Gradually migrate existing Redux applications.

Compare it to other state management libraries: Kea vs setState, Redux, Mobx, Dva, JumpState, Apollo, etc.

Thank you to our sponsors!

Support this project by becoming a sponsor.

Your logo will show up here and on kea.js.org with a link to your website.

How does it work?

In Kea, you define logic stores with the kea({}) function.

Each logic store contains actions, reducers and selectors.

kea({
  actions: ({}) => ({ }),
  reducers: ({ actions }) => ({ }),
  selectors: ({ selectors }) => ({ })
})

They work just like in Redux:

  • They are all pure functions (no side effects, same input = same output)
  • Actions are functions which take an input and return a payload
  • Reducers take actions as input and return new_data = old_data + payload
  • Selectors take the input of multiple reducers and return a combined output

See here for a nice overview of how Redux works: Redux Logic Flow — Crazy Simple Summary

For example, to build a simple counter:

kea({
  actions: () => ({
    increment: (amount) => ({ amount }),
    decrement: (amount) => ({ amount })
  }),

  reducers: ({ actions }) => ({
    counter: [0, PropTypes.number, {
      [actions.increment]: (state, payload) => state + payload.amount,
      [actions.decrement]: (state, payload) => state - payload.amount
    }]
  }),

  selectors: ({ selectors }) => ({
    doubleCounter: [
      () => [selectors.counter],
      (counter) => counter * 2,
      PropTypes.number
    ]
  })
})

The logic stores can either

  1. be wrapped around your component or pure function:
const logic = kea({ /* options from above */ })

class Counter extends Component {
  render () {
    const { counter, doubleCounter } = this.props
    const { increment, decrement } = this.actions

    return <div>...</div>
  }
}

export default logic(Counter)
  1. used as decorators:
@kea({ /* options from above */ })
export default class Counter extends Component {
  render () {
    return <div />
  }
}

or

  1. imported and then connected to:
// features-logic.js
import { kea } from 'kea'
export default kea({ /* options from above */ })

// index.js
import { connect } from 'kea'
import featuresLogic from 'features-logic'

@connect({
  actions: [
    featuresLogic, [
      'increment',
      'decrement'
    ]
  ],
  props: [
    featuresLogic, [
      'counter',
      'doubleCounter'
    ]
  ]
})
export default class Counter extends Component {
  render () {
    return <div />
  }
}

You can also connect logic stores together, to e.g:

... use actions from one logic store in the reducer of another. ... combine reducers from multiple logic stores into one selector.

Eventually you'll need side effects. Then you have a choice.

You can use simple thunks via redux-thunk:

import 'kea-thunk'
import { kea } from 'kea'

const incrementerLogic = kea({
  actions: () => ({
    increase: true
  }),
  reducers: ({ actions }) => ({
    counter: [0, PropTypes.number, {
      [actions.increase]: (state, payload) => state + 1
    }]
  }),
  thunks: ({ actions, dispatch, getState }) => ({
    increaseAsync: async (ms) => {
      await delay(ms)
      await actions.increase()
    }
  })
})

.... or the more powerful sagas via redux-saga.

(coming soon: support for epics with redux-observable)

Check out the examples on the homepage or start reading the guide for more.

If you're already using Redux in your apps, it's really easy to migrate.

Installation

First install the packages:

# if you're using yarn
yarn add kea redux react-redux reselect

# if you're using npm
npm install kea redux react-redux reselect --save

Then configure the Redux store. You may either do it manually or use the getStore helper. We recommend using the helper, as it will also configure any installed plugins (e.g. kea-saga). You may pass additional middleware and reducers as options.

First, create a file called store.js with the following content:

// store.js
import { getStore } from 'kea'

export default getStore({
  // additional options (e.g. middleware, reducers, ...)
})

Then import this in your app's entrypoint before any calls to kea() are made. In practice this means you should import your store before your root component.

Finally, wrap your <App /> with Redux's <Provider />.

This is how your entrypoint would look like if you used create-react-app:

// index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux'; // <--- add this

import './index.css';

import store from './store'; // <--- add this BEFORE App
import App from './App';
import registerServiceWorker from './registerServiceWorker';

ReactDOM.render(
  <Provider store={store}> // <-- add this
    <App />
  </Provider>,
  document.getElementById('root')
);

registerServiceWorker();

Scaffolding

You may also use the CLI tool to start a new Kea project:

npm install kea-cli -g
kea new my-project
cd my-project
npm install # or yarn
npm start   # or yarn start

and open http://localhost:2000/.

Later inside my-project run these to hack away:

kea g scene-name                               # new scene
kea g scene-name/component-name                # component under the scene
kea g scene-name/component-name/really-nested  # deeply nested logic

More documentation coming soon! Please help if you can!

Contributors

This project exists thanks to all the people who contribute. [Contribute].

Backers

Thank you to all our supporters! 🙏 [Become a backer]

You can’t perform that action at this time.