> ## Documentation Index
> Fetch the complete documentation index at: https://docs.hana.leafphp.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Reducers

> Abstract multiple state actions into a single store function

Hana allows you easily set and get your global state using the `useStore()` hook, and while this is super easy, it quickly gets annoying if you have to work with multiple state values, especially if they are all working towards the same feature.

Reducers allow you to abstract all that into a single function which can be called from anywhere in your app, using the `useReducer()` hook.

## Defining a reducer

At the core, a Hana reducer is just a function that accepts two arguments:

* The current global state
* A payload passed in from when the function is called

```tsx theme={"theme":"ayu-dark"}
const setFromPayload = (state, payload) => {
  	// Perform some operations
  	return {
		...state,
		...payload,
	};
};
```

This function returns a new application state, while allowing you to perform additional actions.

## Registering a reducer

Hana reducers are registered globally so they can be used anywhere in your app without carrying over the entire function as done in other reducer implementations. In Hana, all you need is the reducer name. You can register the reducer globally using:

* The `createStore()` function right on init
* `useReducer()` but this can cause problems if not done right

### Using `createStore()`

`createStore()` is OPTIONALLY used to initialize your global store with default options like the initial state, reducers, modules and other items. To add reducers, you can either [use a module](/state/modules) or pass the reducer directly like this:

```tsx theme={"theme":"ayu-dark"}
import { createStore } from '@hanabira/store';

createStore({
  ..., // Other config
  reducers: {
    setItems: (state, payload) => {
      // perform some operation
      const items = state.items.reverse();

      return {
        items: [
          ...items,
          ...payload
        ],
      };
    },
  },
});
```

The example above registers a reducer called `setItems` that reverses the order of the items in the state object and adds the payload to the end of the array. This reducer can be used in any component using the `useReducer()` hook, but we will get to that later.

### \*\*Using \*\*`useReducer()`

This hook takes in the reducer function you want to register, and uses the name of the function as the name of the reducer. This means that the name of the reducer function must be the same as the name of the reducer you want to register.

<Tip>
  We recommend using `createStore()` to register all your reducers instead of `useReducer()` because this method heavily depends on execution order. If the user calls a component that requires the reducer before it is registered, you could break your application. You should use this method to register your reducers ONLY if you can guarantee the correct execution order
</Tip>

```tsx theme={"theme":"ayu-dark"}
import { useReducer } from '@hanabira/store';

const setItems = (state, payload) => {...};

const Component = () => {
  const addToList = useReducer(setItems);

  return (
    <div>
      <button onClick={() => addToList(['New item'])}>Add to list</button>
    </div>
  );
};
```

In this case, the reducer is passed directly to `useReducer()` . It will take the function name which is `setItems()` in this case, and register it globally so you can use it in other components without needing to export the function first:

```tsx theme={"theme":"ayu-dark"}
import { useReducer } from '@hanabira/store';

const Component = () => {
  const setItems = useReducer('setItems');

  // items is an array of items the user wants to add to the list
  const addItemsToList = (items) => {
    setItems(items);
  };
  
  ...
};
```

<Warning>
  Remember that this will only work if the component with the initial `useReducer()` is called first
</Warning>

## Using a reducer

After registering your reducer globally, the easy part is using your reducer to do all the cool magical state updates with just one function. Let's look at an example where some data is collected from an API response and synced to state:

```tsx theme={"theme":"ayu-dark"}
const [, setUser] = useStore('user');
const [, setWallets] = useStore('wallets');
const [, setRecentContacts] = useStore('recentContacts');

...

const setDataFromResponse = async () => {
	const data = await getResponse();

	setUser(data.user);
	setWallets(data.wallets);
	setRecentContacts(data.recentContacts);
}
```

While this isn't too bad, our `setItems()` from will allow us to do this same thing in a much more elegant way:

```tsx theme={"theme":"ayu-dark"}
const writeToStore = useReducer('setItems');

...

const setDataFromResponse = async () => {
	const data = await getResponse();

	writeToStore({
		user: data.user,
		wallets: data.wallets,
		recentContacts: data.recentContacts,
	});
}
```

While this is a super simple example and will probably not happen much in production, the idea is the same. Reducers allow you to define some actions that return a new state and are usually used for complex flows.

## Reducers with no values

Most implementations of reducers force you to pass a payload into your reducer function, but that's totally optional with Hana. This allows you to define self-contained reducers that perform and internal action and update the state, for example, a logout action:

```tsx theme={"theme":"ayu-dark"}
import { createStore } from '@hanabira/store';

createStore({
  reducers: {
    logout: (state) => ({
      ...state,
	  token: null,
	  refreshToken: null,
	  user: null,
	  anythingElseToUnset: null,
    }),
  },
});
```

And then use it like this:

```tsx theme={"theme":"ayu-dark"}
import { useReducer } from '@hanabira/store';

const LogoutButton = () => {
  const logout = useReducer('logout');

  return <button onClick={logout}>Logout</button>;
};
```

## Reducers with async actions

Hana reducers aren't just a handy way of setting your state values, you can also use them to perform async actions like fetching values from an API:

```tsx theme={"theme":"ayu-dark"}
import { createStore } from '@hanabira/store';

createStore({
  reducers: {
    addWallet: async (state, payload) => {
      const response = await linkNewWallet(payload);

      return {
        ...state,
		balance: response.data.balance,
		wallets: [
		  ...state.wallets,
		  response.data.wallet,
		],
      };
    },
  },
});
```

And then you can use this `addWallet()` reducer to add a new wallet and update the user's balance in one elegant line:

```tsx theme={"theme":"ayu-dark"}
import { useReducer } from '@hanabira/store';

const Component = () => {
  const addWallet = useReducer('addWallet');

  const addToList = async () => {
    await addWallet({...});
  };

  ...
};
```

## Skip re-rendering UI

Sometimes, you may need to use a reducer in a component that does not actually re-render the UI after the reducer is called. In this case, you can use the `useStaticReducer()` hook. It works exactly like the `useReducer()` hook, but it does not cause the component to re-render when the reducer is called.

```tsx theme={"theme":"ayu-dark"}
import { useStaticReducer } from '@hanabira/store';

const Component = () => {
  const setItems = useStaticReducer('setItems');

  const addToList = (items) => {
    setItems(items);
  };

  ...
};
```
