Documentation
Concepts
Slice

Slice

Slices are central to managing your app's state. They bundle together actions, state fields, derived fields, and effects for cleaner and efficient state management.

To create a slice:

counter-slice.ts
import { createKey } from '@nalanda/core';
 
const key = createKey('counter-slice', []);
 
// Initialize a Fields
const counterField = key.field(0);
 
// Define some actions
function incrementAction() {
  return counterField.update((value) => value + 1);
}
 
// export the slice with all the fields and actions 
// you want to expose to the rest of the app
export const counterSlice = key.slice({
  counter: counterField,
  incrementAction,
});
💡

Always be selective when exporting fields and actions. It's a best practice to expose only what's necessary, keeping rest internal.

Registering a Slice

For a slice to be operational, it must be registered with the store:

import { createStore } from '@nalanda/core';
 
const store = createStore({
  slices: [counterSlice],
});

Accessing the field data

You can access the exposed field's data by calling .get on the slice:

export const counterSlice = key.slice({
  // list all the fields you want to expose
  counter: counterField,
  doubleCounter: doubleCounterField,
  incrementAction,
});
 
// Accessing the exposed data
const { counter } = counterSlice.get(store.state);
console.log(counter); // 0 (initial value)

Updating Slice data

You can call an action directly on the slice to update the state:

// Dispatching the action
store.dispatch(
  counterSlice.incrementAction()
);
 
// state will now be updated
const { counter, doubleCounter } = counterSlice.get(store.state);
 
console.log(counter); // 1
console.log(doubleCounter); // 2

Usage

You can utilize slices in UI components, effects, or within other slices wherever there's access to the store or store state.

Within Another Slice

Below, the counterSlice is utilized within another slice's action:

is-odd-even-slice.ts
import { createKey } from '@nalanda/core';
import { counterSlice } from './counter-slice';
 
// Pass counterSlice as a dependency
const key = createKey('is-odd-even', [counterSlice]); 
 
const isOdd = key.derive((state) => {
  const { counter } = counterSlice.get(state);
  return counterField % 2 === 0;
});
 
const isEven = key.derive((state) => {
  const { counter } = counterSlice.get(state);
  return counter % 2 === 1;
});
 
export const isOddEvenSlice = key.slice({
  isOdd,
  isEven,
});

Within an Effect

You can use a slice in another slice's Effect:

is-odd-even-slice.ts
import { counterSlice } from './counter-slice';
 
// Pass counterSlice as a dependency
const key = createKey('is-odd-even', [counterSlice]); 
 
key.effect((store) => {
  const { counter } = counterSlice.get(store.state);
  if (counter % 2 === 0) {
    console.log('Even');
  } else {
    console.log('Odd');
  }
});

In a React component

You can read data from Slice in a React component:

Counter.tsx
 
import { useStore } from '@nalanda/react';
import { counterSlice } from './counter-slice';
 
export function Counter() {
  const store = useStore();
  const { counter } = counterSlice.get(store.state)
 
  return (
    <div>
      <p>Counter: {counter}</p>
    </div>
  );
}

For more information on using slices in React components, see usage with React.

Best practices

  1. Export slice only: Only export the slice and nothing else from the file:
is-odd-even-slice.ts
// ❌ Don't do this - fields should never be exported
import { counterField } from './counter-slice';
 
// ✅ Do this - use slice to access data in fields
import { counterSlice } from './counter-slice';
 
// ✅ to access the counter field data
counterSlice.get(store.state).counter; // 0
  1. One slice per file: Keep a single slice per file to streamline locating slices and their dependencies.
is-odd-even-slice.ts
 
// ❌ Don't do this - multiple slices in a single file
const oddSlice = key.slice({
  isOdd,
});
const evenSlice = key.slice({
  isEven,
});
 
// ✅ Do this - one slice per file, per key
const oddEvenSlice = key.slice({
  isOdd,
  isEvent
});