import { Meta } from '@storybook/addon-docs';

<Meta title="Docs/Getting Started/State management" />

# State management

<br />

## Communication between components

Some components need to share data with other components in real time, but because they are placed in different app containers inside the theme, they cannot pass props through a parent -> children relationship. For that, we use `zustand` as a state-management utility. Shared zustand states are in the `src/store` directory, and can be imported in any component that needs to share states. States are used similarly to `useState` or `useReducer` hooks, but the difference is that there is only one instance of each state slice, which can be shared among multiple components.

For example, the `ProductListing` and `ProductListingControls` are two components that need to interact. In this case, the listings need to pass data to the controls to display the selected items, but in theory the communication could be in both directions.

The state, simplified for the sake of the example, consists of a data part and a function to alter it:

```javascript
export const [compareProductsStore] = create(set => ({
    selected: [],
    toggle: itemId => set(state => {
        const selected = [...state.selected];
        const itemIndex = list.indexOf(itemId);
        // item was in the array, toggle it by removing
        if (itemIndex !== -1) {
            selected.splice(itemIndex, 1);
        } else {
            selected.push(itemId);
        }
        return {
            selected
        };
    })
}));
```

It is important to note that the reducer function must return a new instance of the data, not the mutated old state.

Then, the component in which you select items needs to import the method to alter the state, and call it when an item is selected:

```jsx
import compareProductsStore from 'compareProducts';

export const ProductListing = props => {
	const { selected, toggle } = compareProductsStore();
	return (
		<div>
			{props.items.map(item => {
				const isItemSelected = selected.indexOf(item.id) !== -1;
				return <button key={item.id} onClick={() => toggle(item.id)}>{`${isItemSelected ? 'deselect' : 'select'} ${item.name}`}</button>
			}}
		</div>
	);
};
```

Up to this point, there is not much difference between that and a `useReducer` that would be extracted to a custom hook. The difference occurs when the same state is imported in another component:

```jsx
import compareProductsStore from 'compareProducts';

export const ProductListingControls = props => {
	const { selected } = compareProductsStore();
	return (
		<ul>
			{props.items.map(item => {
				const isItemSelected = selected.indexOf(item.id) !== -1;
				return (
					<li key={item.id} className={isItemSelected ? 'selected' : 'deselected'}>{item.name}</li>
				);
			}}
		</ul>
	);
};
```
The second component uses the same instance of `selected` data that was modified by the other component, so that changes made in one are displayed in the other, without the need for a common ancestor for the state to be lifted in.

For more information about zustand, see the project's [Github page](https://github.com/pmndrs/zustand).