Effects
Effects help you perform side effects in your application. They come in handy for tasks like data fetching, logging, updating state or direct browser interactions.
import { createKey } from '@nalanda/core';
import { userSlice } from './user-slice';
import { loginSlice } from './login-slice';
const key = createKey('greeting-slice', [userSlice, loginSlice]);
key.effect((store) => {
// effect will rerun whenever userName or isLogged changes
const { userName } = userSlice.track(store);
const { isLoggedIn } = loginSlice.track(store);
if (isLoggedIn) {
console.log(`The user ${userName} is logged in`);
} else {
console.log(`Please login ${userName}`);
}
});
Note: Effects are executed at least once after the store initializes.
Tracking
Effects track any changes of select slice fields. Should a change occur, the effect is re-executed.
You have two syntax options for tracking:
Destructured form
This allows you to declare the values you are interested in and effect will only rerun if any of those values change.
key.effect(store => {
const { userName, userAddress } = userSlice.track(store);
console.log(userName, userAddress);
})
Tracking will only happen if you access the field names in the returned object. It is recommended that you destructure and keep all tracking code at the top of the effect.
Example:
// ❌ Don't do this
doSomething(slice.track(storeState))
// ✅ Do this - tracking works the magic if you access the keys in the object
const { counter } = slice.track(storeState)
doSomething(counter)
Individual access
If you donot like destructuring, you can track a single field directly using the trackField
method.
key.effect(store => {
const userName = userSlice.trackField(store, 'userName');
const userAddress = userSlice.trackField(store, 'userAddress');
console.log(userName, userAddress);
})
Async Effects
Effects can also be async. When an effect is re-invoked before its prior run completes, the cleanup function can help manage any necessary cleanups, ensuring consistency.
import { cleanup } from '@nalanda/core';
key.effect(async (store) => {
const { userName } = userSlice.track(store);
const controller = new AbortController();
// called when effect is re-invoked
// in this case when userName changes
cleanup(store, () => {
controller.abort();
});
const data = await fetchUserData(userName, {
signal: controller.signal,
});
store.dispatch(userSlice.updateData(data));
});
If you are unfamiliar with AbortController, you can read more about them here (opens in a new tab).
How to access values without tracking ?
See Accessing values without tracking.