---
title: Shared state
description: >-
version: 11.17.0
generatedAt: 2026-11-05T09:55:45.843Z
checksum: 090b7d977ba4be5e2c4c04d199a30a4048416c59f443a56985df2f80629d9c40
---

# Shared state

Share state between components using a common identifier. Each component receives updates automatically, without a Context provider.

Use it when components need the same state but live in different parts of your application. For state used by one component, React's `useState` is usually enough.

## Import

```tsx
import {
  useSharedState,
  useWeakSharedState,
  createSharedState,
} from '@dnb/eufemia/shared'
```

The hook also has a default export, so you can choose your own name:

```tsx
import useStore from '@dnb/eufemia/shared/useSharedState'
```

## Share between components

Both components below use the same ID. Increase the counter and the summary updates too.


```tsx
function Counter() {
  const {
    get,
    extend,
    set
  } = useSharedState('shared-state-counter-demo', {
    count: 0
  });
  return <Flex.Horizontal>
              <Button onClick={() => extend({
      count: get().count + 1
    })}>
                Increase
              </Button>
              <Button variant="secondary" onClick={() => set({
      count: 0
    })}>
                Reset
              </Button>
            </Flex.Horizontal>;
}
function Summary() {
  const {
    data
  } = useSharedState('shared-state-counter-demo', {
    count: 0
  });
  return <P aria-live="polite">Count: {data.count}</P>;
}
render(<Flex.Stack>
            <Counter />
            <Summary />
          </Flex.Stack>);
```


`initialData` seeds an empty store. Joining an existing store keeps its current value. Use the same TypeScript data type wherever you use an ID.

## Read and update

`useSharedState(id, initialData?)` returns:

| Member          | Purpose                                                                          |
| --------------- | -------------------------------------------------------------------------------- |
| `data`          | Current value. The component re-renders when it changes.                         |
| `get()`         | Read the latest value immediately, including inside callbacks.                   |
| `set(value)`    | Replace the whole value.                                                         |
| `extend(value)` | Shallow-merge object properties. Replace arrays and other values.                |
| `update(value)` | Replace the value, like `set`, without calling the optional `onChange` callback. |

```tsx
const { data, get, set, extend } = useSharedState('app-preferences', {
  currency: 'NOK',
  language: 'en',
})

extend({ currency: 'EUR' }) // Keeps language
set({ currency: 'NOK', language: 'nb' }) // Replaces the whole object
```

Call updates in event handlers or effects. Pass values directly; updater functions such as `set(previous => ...)` are not supported. Replace nested objects and arrays when changing them.

`set` and `extend` return `true` when the value changes. Shallow-equal values do not trigger another update. If needed, pass `onChange` as the third hook argument to handle changes made through the hook's `set` or `extend`.

## Update outside React

`createSharedState(id, initialData?)` accesses the same store without subscribing. Use its `get`, `set`, `extend`, or `update` methods in regular functions, such as an API response handler. Mounted hooks receive the updates.


```tsx
function selectCurrency(currency: string) {
  const store = createSharedState('shared-state-currency-demo', {
    currency: 'NOK'
  });
  store.extend({
    currency
  });
}
function Currency() {
  const {
    data
  } = useSharedState('shared-state-currency-demo', {
    currency: 'NOK'
  });
  return <Flex.Stack>
              <Flex.Horizontal>
                <Button onClick={() => selectCurrency('NOK')}>
                  Use NOK
                </Button>
                <Button onClick={() => selectCurrency('EUR')}>
                  Use EUR
                </Button>
              </Flex.Horizontal>
              <P aria-live="polite">Selected currency: {data.currency}</P>
            </Flex.Stack>;
}
render(<Currency />);
```


## Keep or clear state

`useSharedState` keeps its value after components unmount. Use `useWeakSharedState` in every subscriber for an ID when the value should reset after the last subscriber unmounts.


```tsx
function Counter() {
  const {
    data,
    get,
    extend
  } = useWeakSharedState('shared-state-weak-demo', {
    count: 0
  });
  return <Flex.Horizontal align="center">
              <Button onClick={() => extend({
      count: get().count + 1
    })}>
                Add one
              </Button>
              <P aria-live="polite">Temporary count: {data.count}</P>
            </Flex.Horizontal>;
}
function Example() {
  const [visible, setVisible] = useState(true);
  return <Flex.Stack>
              <Button variant="secondary" onClick={() => setVisible(!visible)}>
                {visible ? 'Unmount counter' : 'Mount counter'}
              </Button>
              {visible && <Counter />}
            </Flex.Stack>;
}
render(<Example />);
```


## Choose an ID

- Use a stable, non-empty string unique to the feature, such as `'my-app:preferences'`. Matching IDs share state, even across separate React roots using the same module instance.
- A stable object reference also works. Create it outside the component or keep it in a ref.
- An absent ID disables the hook: `data` is `undefined` and updates do nothing.

State lives in memory and is not persisted across reloads or shared between browser tabs. By default, each loaded copy of Eufemia has its own store. To share state across independently bundled copies in the same browser window, use the same ID and `scope`:

```tsx
useSharedState('preferences', initialData, undefined, { scope: 'my-app' })
createSharedState('preferences', initialData, { scope: 'my-app' })
```

During server rendering, keep user-specific state request-scoped; fixed IDs in a long-lived server module can share data between requests. For hydration, the hook's fourth argument also accepts `getServerSnapshot`, which should return the same initial value on the server and client.
