Advanced Topics
note
Here are some more things you can do with Kea. You probably won't need use them, yet the information is here in case you do.
Lifecycles#
Kea's logic has three different states:
- Initialized. When your JavaScript interpreter encounters a
const logic = kea(input)call, not much happens. It just stores theinputvariable on the logic and goes on. No processing takes place. - Built. When a logic is needed, it must first be built. This means converting
an
inputsuch as{ actions: { ... } }into actual functions onlogic.actionsthat can be called. Same for all thereducers,selectors, etc. - Mounted. Once a logic is built, it can be mounted. This means attaching the
reducersto Redux, registering all thelisteners, etc.
If you use Kea outside of React, you have to mount and unmount your logic manually.
Read the next section for instructions on how to do so.
If you use Kea with React, every time you render a component that access a logic
via useValues, useActions or some other method, the logic is built and mounted automatically. When all components
that use a logic are removed from React's tree, that logic will be unmounted automatically.
Only logic which is actively in use will be mounted and attached to Redux.
Mounting and Unmounting#
When you use Kea with React, there's a lot that is handled for you behind the scenes.
For example logic is mounted automatically with your <Component /> and unmounted when it's no longer needed.
Sometimes however, you wish to manually mount logic. For example to already start loading data in
your router before transitioning to a component... or in getInitialProps in next.js... or when writing
tests with Jest.
Perhaps you even want to use Kea with a framework other than React.
In any case, just call mount() on your logic and get as a reply a function that will unmount it:
In case you need to pass props to your logic, for example if it is keyed,
you should build the logic explicitly before calling mount() on it:
There are a few other options you can use. See the logic API for more details.
Calling logic.mount() inside listeners#
In Kea 2.0 logic automatically connects when used inside another logic.
Assuming counterLogic is not used anywhere else, when called in the listener here,
it will be automatically built and mounted:
It will also remain mounted for as long as logic is mounted.
What if you don't want that and instead prefer to mount and unmount counerLogic manually within
the listener?
A practical example of this is to mount a logic to preload data on a route change 150ms before transitioning the scene... and then to unmount it manually once the page loaded. It's enough to prevent the "flash of loading" in most cases.
Instead of directly calling logic.mount(), you just need to build the logic fist, even if it
doesn't need any props. You must then pass false as the second argument to .build:
Instead of using logic(props) to build the logic, use logic.build(props, false).
Without explicitly setting this second argument (autoConnectInListener) to false,
counterLogic would have been automatically built and mounted on counterLogic.values.
Calling .mount() on a built and mounted logic won't mount it twice, but it will stay mounted
until the returned unmount is called, even if no other logic is connected to it.
Extending logic#
Up until a logic has been built and mounted, you can extend it:
Extending logic is especially powerful when writing plugins. For example to dynamically add actions, reducers or listeners to a logic, based on some key.
Props in Selectors#
Since selectors need to be recalculated when their inputs change, there's a twist when
using props with them.
Take the following buggy code:
The code will work, but only partially.
The problem is that the value of diffFromDefault will only be updated when counter changes,
but not when props.defaultCounter changes.
What if we would also like to update the selector when the props change?
Previously we defined a selector as a function like this:
That's an incomplete definition. All selectors have a second argument called props.
To make your new selector update itself when props change, use an inline
selector that picks the right value from props:
Shared listeners#
If multiple listeners need to run the same code, you can:
- Have all of them call a common action, which you then handle with another listener:
This however dispatches a separate action, which is then listened to.
- If you want to share code between listeners without dispatching another action, use
sharedListeners:
That function will be called directly, without an action being dispatched in the middle.
You might still prefer to explicitly dispatch an action, as that level of abstraction may be better suited for the task at hand. You can use the shared action in a reducer for example.
Next steps
- For even more advanced topics, read Migrating from Redux to learn how Kea and Redux interact under the hood.