All notable changes to this project will be documented in this file.
- Increase the amount of supported selectors in a selector's input from 11 to 16.
- Fix bug with deriving default key from undefined props.
- Support searching by key in
logic.findMounted(123)
andlogic.isMounted('string key')
. - Adds
logic.find(keyOrProps?)
, which throws if the logic is not mounted.
- Release with experimental
KeaLogicType
type builder (experimental only in 3.1.x).
- Add
useAsyncActions
hook
- Add support for
asyncActions
:
const logic = kea([
actions({
fetchUser: (id: number) => ({ id }),
}),
listeners({
fetchUser: async ({ id }, breakpoint) => {
await breakpoint(100)
const user = await fetch(`https://example.com/users/${id}`)
breakpoint()
return user
},
}),
])
const user = await logic.actions.fetchUser(1)
The promise returns whatever is returned in the first listener that listens to this action. Ususally that's the output of the only listener is the same logic that creates the action.
In case you use breakpoints, and the action is called multiple times, all the promises will resolve when the last called action returns.
That means in the case of
const promise1 = logic.actions.fetchUser(1)
const promise2 = logic.actions.fetchUser(1)
Both promises will resolve at the same time. The first dispatch one that breaks will resolve when the second one finishes.
To make this work, each created action now also comes with an ever-increasing dispatchId
:
logic.actionCreators.fetchUser(123) ===
{
type: 'fetch user (logic)',
payload: { id: 123 },
dispatchId: 1,
}
To disable setting dispatchId
and hence support for async actions, call resetContext({ disableAsyncActions: true })
.
- Make
logic.props
mutable, and store props input immutably inlogic.lastProps
. This fixes a bug:
const propValues = []
const logic = kea([
actions({ doStuff: true }),
listeners(({ props }) => ({
doStuff: () => {
propValues.push(props.value)
},
})),
])
logic({ value: 0 }).mount()
logic({ value: 1 }).actions.doStuff()
logic({ value: 2 }).actions.doStuff()
Previously propValues
would contain [0, 0]
, but now it contains [1, 2]
.
- Support "prop selectors" in selectors. Now
p.id
is a shorthand for(_, props) => props.id
. For example:
const logic = kea([
props({} as { id: number }),
selectors({
duckAndChicken: [(s, p) => [s.duckId, s.chickenId, p.id], (duckId, chickenId, id) => duckId + chickenId + id],
}),
])
- Show better errors in production
- Remove reference to
window
fromhooks.ts
- Remove incorrect
peerDependencies
frompackage.json
- Read more here: https://keajs.org/blog/kea-3.0
-
Update version requirements of peer dependencies:
reselect
4.1+,redux
4.2+,react-redux
7+ andreact
16.8+. -
If you're using React 18, upgrade
react-redux
to version 8+. -
Add a "redux listener silencing store enhancer", which prevents Redux's
useSelector
s from updating, when mounting a logic from within the body of a React component (e.g. withuseValues
). This effectively silences log spam in React 18 (Warning: Cannot update a component (
Y) while rendering a different component (
X). To locate the bad setState() call inside
X, follow the stack trace as described.
), and improves performance. -
Set the
autoConnectMountWarning
option totrue
by default. Kea 2.0 introduced "auto-connect", and while it works great in reducers and selectors, automatically connecting logic in listeners turned out to be a bad idea. Thus, in Kea 2.6, when accessing values on an unmounted logic, you'll get a warning by default. In Kea 3.0, it will trigger an error.
import { kea } from 'kea'
import { otherLogic } from './otherLogic'
import { yetAnotherLogic } from './yetAnotherLogic'
const logic = kea({
// connect: [otherLogic], // should have been explicitly connected like this, or mounted outside the logic
actions: { doSomething: true },
listeners: {
doSomething: () => {
// This will now print a warning if `otherLogic` is not mounted.
console.log(otherLogic.values.situation)
},
},
reducers: {
something: [
null,
{
// This `yetAnotherLogic` will still get connected automatically, not print a warning,
// and not require `connect`. That's because it's connected directly at build time, whereas
// in the listener, we're running within an asynchronous callback coming from who knows where.
// While this works, it's still good practice to explicitly define your dependencies.
[yetAnotherLogic.actionTypes.loadSessions]: () => 'yes',
},
],
},
})
- Support custom selector memoization. Use
memoizeOptions
as the 4thselector
array value, which is then passed directly to reselect:
const logic = kea({
selectors: {
widgetKeys: [
(selectors) => [selectors.widgets],
(widgets) => Object.keys(widgets),
null, // PropTypes, will be removed in Kea 3.0
{ resultEqualityCheck: deepEqual },
],
},
})
- Add
isEqual(a: any, b: any)
as the 4th argument to the selector array, afterPropTypes
. This will change to the 3rd element in Kea 3.0, which is in active development. The fix was backported from Kea 3.0.
- Add
resetContext()
optionautoConnectMountWarning
, which warns when a logic is automatically mounted in a listener.
- In keyed logics,
path: ['without', 'key']
now expands topath: (key) => ['without', 'key', key]
.
- Add
previousLocation
5th argument tourlToAction
.
useMountedLogic
now returns the built logic with the right type.
- Add support for connecting to actions in circularly connected logics (
aLogic
connects tobLogic
to getbAction
,bLogic
connects toaLogic
to getaAction
).
- Add support for connecting to values in circularly connected logics (
aLogic
connects tobLogic
to getbValue
,bLogic
connects toaLogic
to getaValue
).
- Add
logic.findMounted(props)
that either returns thebuiltLogic
ornull
logic.isMounted(props)
now accepts props to check the mounted status of keyed logics without building them.
- Update types for
urlToAction
forkea-router
- Improve performance of
logic.isMounted()
- Improve
Can not access "actions" on logic "kea.logic.1" because it is not mounted!
error #140 @pauldambra
- Add
logic(props).isMounted()
#141
- Break listeners if resetContext called before a breakpoint
- Store key of the listener with the pending promises
- Track pending listeners, mainly for usage in tests
- Fix
preloadedState
type
- Add support for TypeGen plugins inside logic
input
- Switch from Enzyme to React Testing Library
- Export more types
- Add even more betterer types for the
kea-router
plugin
- Add even better types for the
kea-router
plugin
- Add better types for the
kea-router
plugin
- Added basic support for inheritance with:
const logic = kea({ inherit: [otherLogic], actions: {...} })
. This makes a copy of the inputs forotherLogic
. Actions and values will not be shared between the two logics.
- Support passing
LogicType
tologic.extend<LogicType>()
- Fixed recursive
.exend()
. This works now:kea({ extend: [{ extend: [ ... ] }] })
) - Please note that
logic.extend()
alters the existing logic. It does not clone nor inherit logic inputs. - To clone a logic, use
kea({ extend: [...otherLogic.inputs, { actions: {}, /* new stuff */ }] })
. Better API coming soon.
- Possibly Breaking: Changed the default path for logic
without a
path
(or when not using the kea babel plugin) fromkea.inline
tokea.logic
. If you have ever hardcoded"kea.inline"
anywhere, perhaps in tests, this will cause a bit of headache. If you need it set atkea.inline
, useresetContext({ defaultPath: ['kea', 'inline'] })
. - Added
<Provider />
tag to simplify calling React-Redux's<Provider store={getContext().store} />
. - Fixed crashes with React Fast Refresh.
- Fix regression introduced in 2.3.5 with default keys like:
key: props => props.id || 'default'
- Improve types and build
- Improve types
- Fix issue with .mount() overriding props pased to logic inside selectors #124
- Add types for arrays of listeners (was supported, just not typed)
- Add types for using selectors as defaults in reducers
- Add generics to the
BuiltLogic<logicType>
andLogicWrapper<logicType>
types.
- Fix edge case error when removing listeners (@zshannon #108)
- Nicer error when accessing something in the store that doesn't exist
-
Adds
<BindLogic logic={keyedLogic} props={{ id: 12 }}>
, which passes a specific build ofkeyedLogic
via React Context down to nested components. This build will be used when calling a hook likeuseValues(keyedLogic)
without props.Essentially, you pass the props without actually passing the props.
- Create store automatically if calling
resetContext
, except for the default initial context.
- Improve a few types for plugins
- TypeScript support!
- Fix bug with the store being created twice. #111
- No other breaking changes.
- Read the blog post: https://kea.js.org/blog/kea-2.1
- Simplified the syntax even more! You don't need to pass
() => ({ ... })
toactions
,reducers
, etc if there's nothing you want from the logic. Just pass{}
instead. - Simplified syntax for selectors when not using the function syntax:
kea({
selectors: {
doubleCounter: [(selectors) => [selectors.counter], (counter) => counter * 2],
},
})
- Listeners get the store's
previousState
as their 4th argument. You can use selectors (selectors.myData(previousState)
) to get the any value as it was before the action was dispatched.
- Fix error when calling old references to actions on unmounted logic via hooks.
Version 2.0 brings a lot of convenience features and one breaking change. The changes are briefly described below. Read the announcement blog post to get more context: https://kea.js.org/blog/kea-2.0
There's also a new babel plugin you might want to check out: https://github.com/keajs/babel-plugin-kea
Finally, Kea 2.0 comes with brand new docs on https://v2.keajs.org. (Old docs for 1.0 and 0.28)
- Listeners are now built in to Kea. That means if you were initialising the
listenersPlugin
before inresetContext
, you need to remove it. Otherwise Kea won't start.
- No more need to add the
[actions.
and]
in[actions.yourAction]
when defining reducers and listeners - Auto-Connect: You can now write
otherLogic.actions.doSomething()
as keys for reducers and listeners and inside the executable part of listeners... instead of having toconnect
the values manually. The logic is automatically connected and mounted if it wasn't already. - It's possible to extend reducers with
.extend
. Before if you would define a new reducer with an existing name in theextend
block, it would override the old one completely. Now thery merge and the actions on the old one still continue to work. createStore
is now true inresetContext
. So if you don't need to specify the key at all if you don't have any custom redux middleware.- The
path
in your logic can start with anything. Previously it was justkea
orscenes
unless manually specified. - Instead of passing an array
[default, {..}]
to a reducer, now passing an object{..}
works and sets the default to null.
There are too many changes to list here. See this document for a complete overview!
- Added
logic.withKey(params => params.id)
that you can use to connect dynamic components. See this comment for more details.
- Bigger changes to the plugin system. Please upgrade all plugins (e.g.
kea-saga
) to the supported versions! - Plugins must now be manually installed by either passing them to the
plugins
array ingetStore
, running them throughactivatePlugin()
or importing from'kea-plugin/install'
. See the README of each plugin for details. - Some plugins can now also be installed just for individual logic stores, e.g.
kea-localstorage
. - BREAKING Removed support for
{ persist: true }
to store the output of reducers in LocalStorage. Use thekea-localstorage
plugin to restore support for this feature. - PropTypes are no longer necessary when defining reducers.
- Only mount the reducer in redux, if there's an actual reducer or a manually given path
- Now if you pass a wrapped component (
logic(Component)
) anactions
prop, its conents be merged with the created actions prop.
- Add support for specifying your own compose enhancer in
getStore()
, e.g. for remote-redux-devtools - A lot of code refactoring. The plugins API changed a bit, so upgrade your
kea-saga
andkea-thunk
packages accordingly.
- Kea now supports plugins!
- The previous saga functionality has moved to kea-saga. Please install it to continue using sagas!
- There's a new function,
getStore
, which greatly simplifies configuring your store, especially when importing plugins.
- Removed
Logic
andScene
classes and other old deprecated code. Please make sure your app works with 0.24.1 without warnings before upgrading!
- Leverage action cache to enable parameterized kea logic. See #43 for more details. By @rheng
- Moved CLI tools (the
kea
command line utility) to separatekea-cli
package - Added
"module"
field topackage.json
with a version that uses ESnext imports instead ofrequire
calls. Should decrease bundle size by ~10kb on Webpack 2+, rollup and other module bundlers that use this - Added a
"esnext"
field for people to opt in to the untranspiled source.
- Remove the warning if the path is not yet conencted to Redux (needed for tests)
- Rehydrate the store also for inline kea initializations (when the component has a
key
) - Fix unmounting of sagas (cancelled was not called after start stopped)
- Add connected selectors to selectors in wrapped components
- Fix re-creation of empty
kea({})
root
selectors for shallow comparison - Inject proptypes to components
- Add functions to reset the store cache for tests
- Make sagas work with functional components
- Removed all old deprecations except for the usage of
run
andcancelled
in sagas. These still give warnings. - Added new deprecations for
Logic
andScene
classes and related code. Basically everything imported fromkea/logic
andkea/scene
is no longer safe. Saga
classes and code imported fromkea/saga
are safe for now, but you should migrate it to the unformkea({})
syntax sooner rather than later.
When upgrading, make sure your code works with 0.22.1 without any deprecation warnings. Then upgrade to 0.23.0 and remove the new warnings.
- Added
babel-runtime
. This should reduce the issues users have been having withcreate-react-app
and other situations whereregenerator
is not automatically loaded. Fixes #25.
- When creating actions like
actions: () => { doit: true }
, previously the payload of the action would equaltrue
. Now the payload equals{ value: true }
. This was made so that when we inject thekey
into the payload for actions that are defined on kea logic stores that are directly connected to the component, we would not run into errors. See here for more.
- Added
props
as the second argument to input selectors when creating kea selectors
- Connected sagas are now automatically started, no need to pass them separately in { sagas: [] }
- A saga will not be started if one with the same path is already running
This was a big release. A lot of code changed and we now have many deprecations which should be removed in the next releases to make the bundle smaller.
Before upgrading to any newer version (0.20, etc), make sure your code works fine with 0.19.
- Deprecated:
run
andcancelled
replaced withstart
andstop
in Saga classes - Added inline kea
- New and easier way to hook up to
redux
- Use
this.actions
instead ofthis.props.actions
in components - Deprecated the old Logic and Saga classes in favor of the unified
kea({})
version. No warnings yet. - Added tests for the
kea({})
version.
- Use
store.addKeaScene(savedScene, true)
to load scenes in the background without replacing the sagas of the "active" scene
- PR4. Add action.meta to reducer mapping.
- PR4. Upgrade takeEvery, takeLatest usage for redux-saga >= 0.14 compatibility.
- [BREAKING] The propType is now the 3rd element in the selector array. See here how to refactor.
- Added
@connect
and@initLogic
decorators. Reverse the steps here to upgrade.
- Fixed a bug with kea-cli/generate
- In
kea/logic
, renamedstructure = () = ({})
toreducers = () = ({})
in order to maintain compatibility of terms with redux. - Moved
createScene
,NEW_SCENE
,createCombinedSaga
,getRoutes
,combineScenesAndRoutes
,createRootSaga
andcreateKeaStore
fromkea/logic
tokea/scene
- You no longer need to use
mirrorCreator
or comparable to create constants. Just pass in an array.
- Deprecated
addSelector
in favor of the new easier to read format. See here for an example.
- Deprecated
createMapping
in favor of the new compact Array structure. See here for an example.
- [BREAKING] Changed the name of the project to
kea
fromkea-logic
. Please update and changeimport ... from "kea-logic"
toimport ... from "kea/logic"
- Added the
Saga
class. Here's how to use it.
- [BREAKING] Removed dependency on redux-act
- [BREAKING] Changed format for Logic actions. Now you don't need to run the redux-act createAction() anymore and no description is needed. See the example in README.md or this commit for the new format.
- Removed deprecated createLogic() function
- Exposed functions
createAction
,createActions
,createReducer
- Changed format of
type
to be more readable