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

# Interact with the application state

> How to read and update the Atoti UI Redux state using useSelector and useDispatch from react-redux, including selectors such as getIsPresenting and getDashboardState, dispatching Action types, and extending the state using storeEnhancers in Configuration.

This page shows how to interact with [the application state](../../reference/types#state). In particular, you will learn how to:

* [consume state attributes](#consume-state-attributes)
* [trigger state updates](#trigger-state-updates)
* [extend the state](#extend-the-state)
* [change the initial state](#change-the-initial-state)

<Note>
  The snippets in this page work with the Atoti UI starter. If you have not
  installed it yet, then read [Setup](../../install-and-start/set-up).
</Note>

<Note>
  Atoti uses [Redux](https://redux.js.org/) for state management. A basic
  understanding of it is preferable in order to understand what follows.
</Note>

Consuming and updating the state is possible using two hooks: [useSelector](https://react-redux.js.org/api/hooks#useselector) and [useDispatch](https://react-redux.js.org/api/hooks#usedispatch) from `react-redux`. It works just like when you use Redux to manage the state of any web application. The only difference is that you do not have to create and provide a store, as Atoti UI does it for you.

See more details and examples below.

## Consume state attributes

To retrieve attributes from the state, use [useSelector](https://react-redux.js.org/api/hooks#useselector).

For instance, the following snippet implements a [higher order component](https://reactjs.org/docs/higher-order-components.html) which depends on `isPresenting`. If it is `true`, then it just displays the application, but if it is `false`, then it also displays a custom horizontal application bar to the left of it.

```tsx theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
import React, { ComponentType } from "react";
import { useSelector } from "react-redux";

import { getIsPresenting } from "@activeviam/atoti-ui-sdk";

/**
 * HOC to be used around Atoti, in order to display a custom left bar (except in presentation mode).
 */
export const withLeftBar = (WrappedApplication: ComponentType) => () => {
  const isPresenting = useSelector(getIsPresenting);
  if (isPresenting) {
    return <WrappedApplication />;
  }

  return (
    <div style={{ height: "100%", display: "flex" }}>
      <div style={{ width: 200 }}>Custom left bar</div>
      <div style={{ flexGrow: 1, position: "relative" }}>
        <WrappedApplication />
      </div>
    </div>
  );
};
```

It can then be registered as follows, in your `index.tsx`:

```typescript {1-1,5-5} theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
import { withLeftBar } from "./withLeftBar";

const extension: ExtensionModule = {
  activate: async (configuration) => {
    configuration.higherOrderComponents.push(withLeftBar);
  },
};
```

Like `getIsPresenting` in the example above, more selectors are exported from `@activeviam/atoti-ui-sdk` and allow you to retrieve specific pieces of state:

* [getActiveToolKey](../../reference/functions#getactivetoolkey)
* [getDashboardState](../../reference/functions#getdashboardstate)
* [getIsDeferred](../../reference/functions#getisdeferred)
* [getIsPresenting](../../reference/functions#getispresenting)
* [getHasUnsavedChanges](../../reference/functions#gethasunsavedchanges)
* [getSelectedLeafKey](../../reference/functions#getselectedleafkey)

## Trigger state updates

To update the state, use [useDispatch](https://react-redux.js.org/api/hooks#usedispatch).

For instance, the following snippet implements an application menu item which adds a new empty page to the dashboard each time the user clicks it.

```tsx theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
import { MenuItem, MenuItemProps } from "antd";
import React, { FC } from "react";
import { useDispatch, useSelector } from "react-redux";

import {
  ApplicationMenuItem,
  DashboardPageState,
  addPage,
  getDashboardState,
  pluginWidgetPivotTable,
} from "@activeviam/atoti-ui-sdk";

/** State of the added page */
const addedPage: DashboardPageState = {
  content: { "0": pluginWidgetPivotTable.initialState },
  layout: {
    children: [
      {
        leafKey: "0",
        size: 1,
      },
    ],
    direction: "row",
  },
  name: "New page",
};

/** Menu item component */
const AddPageMenuItemComponent: FC<MenuItemProps> = (props) => {
  const dashboardState = useSelector(getDashboardState);
  const dispatch = useDispatch();
  const handleClicked: MenuItemProps["onClick"] = (param) => {
    if (dashboardState) {
      // Update the state in order to add a new page to the dashboard.
      dispatch({
        type: "dashboardUpdated",
        dashboardState: addPage(dashboardState, { page: addedPage }),
      });
    }
    props.onClick?.(param);
  };
  return (
    <MenuItem {...props} onClick={handleClicked}>
      Add a page
    </MenuItem>
  );
};

/** Menu item that can be wired into the Atoti UI configuration */
export const addPageAppMenuItem: ApplicationMenuItem = {
  component: AddPageMenuItemComponent,
};
```

This menu item can be added into the **Edit** menu as follows, in your `index.tsx`:

```typescript {7-7} theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
import { ApplicationMenu } from "@activeviam/atoti-ui-sdk";

const extension: ExtensionModule = {
  activate: async (configuration) => {
    const editApplicationMenu = configuration
      .leftApplicationMenu[1] as ApplicationMenu;
    editApplicationMenu.children.push(addPageAppMenuItem);
  },
};
```

For more information about the actions you can dispatch in order to update the state, see [Action](../../reference/types#action).

## Advanced use cases

For more advanced use cases such as extending the state or changing the initial state, you can use a tool called a [store enhancer](https://redux.js.org/understanding/thinking-in-redux/glossary#store-enhancer).

Store enhancers allow to hook into the application's Redux store creation. They can be passed through [Configuration](../../reference/types#configuration), in your `index.tsx`:

```typescript {13-13} theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
import { PreloadedState, Reducer, StoreEnhancer } from "redux";

const myStoreEnhancer: StoreEnhancer =
  (createStore) =>
  (reducer: Reducer<any, any>, preloadedState?: PreloadedState<any>) => {
    // ... This store enhancer does nothing ...
    // ... You will see more examples below ...
    return createStore(reducer, preloadedState);
  };

const extension: ExtensionModule = {
  activate: async (configuration) => {
    configuration.storeEnhancers.push(myStoreEnhancer);
  },
};
```

### Extend the state

What if you need to share state (that is not part of the core Atoti UI state) between several components?

With the right store enhancer, your own state can live along the core state, within the Atoti UI store.

For instance, the following store enhancer introduces a boolean attribute called `foo` along with an action to toggle it. It allows your components to use [`useSelector`](#consume-state-attributes) and [`useDispatch`](#trigger-state-updates) in order to consume and update this slice of state.

```typescript theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
import { PreloadedState, Reducer, StoreEnhancer } from "redux";

const fooReducer: Reducer = (state = true, action) => {
  return action.type === "toggleFoo" ? !state : state;
};

/** Store enhancer adding a slice of state called `foo` into Atoti */
const myStoreEnhancer: StoreEnhancer =
  (createStore) =>
  (reducer: Reducer<any, any>, preloadedState?: PreloadedState<any>) => {
    const enhancedReducer: Reducer<any, any> = (state, action) => {
      const nextState = reducer(state, action);
      const nextFoo = fooReducer(state?.foo, action);
      return { ...nextState, foo: nextFoo };
    };
    return createStore(enhancedReducer, preloadedState);
  };
```

### Change the initial state

You can configure the initial state by overriding the [Redux preloaded state](https://redux.js.org/usage/structuring-reducers/initializing-state). For instance, the following store enhancer makes Atoti start up in presentation mode:

```typescript theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
/** Store enhancer allowing to start in presentation mode */
const myStoreEnhancer: StoreEnhancer =
  (createStore) =>
  (reducer: Reducer<any, any>, preloadedState?: PreloadedState<any>) => {
    return createStore(reducer, preloadedState);
    const overriddenPreloadedState = {
      ...preloadedState,
      isPresenting: true,
    };

    return createStore(reducer, overriddenPreloadedState);
  };
```

<Warning>
  Don't forget to forward `preloadedState`, as illustrated in the snippet above.
  Forgetting it can break other store enhancers, possibly registered by other
  Atoti UI extensions.
</Warning>
