Stop managing state
Tags: stateadapt, angular, react, redux
Published: 2023-01-05 09:17:36

---
title: Stop managing state
published: true
description: State adapters are objects that contain reusable logic for changing and selecting from state. There are lots of exciting patterns they enable.
tags: StateAdapt, Angular, React, Redux
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kqzqk2fi4in7xd01sn6l.png
// Image: 
---

[YouTube](https://www.youtube.com/watch?v=-aMgElYZfSw)

Have you ever written state management that looked like this? 
```typescript
return ({
  ...state,
  checked: !state.checked,
});
```

You've probably done this a million times. 

But you won't have to anymore, thanks to state adapters.

## What are state adapters?

State adapters are objects that contain reusable logic for changing and selecting from state. Each state adapter is dedicated to a single state type/interface, which enables portability and reusability. Everywhere you need to manage state with a certain shape, you can use its state adapter. 

If someone just made a boolean state adapter, nobody on Earth would ever need to write that code again. Instead, they could just write something like this:

```tsx
return adapter.toggleChecked(state);
```

Booleans are the simplest type of state, but even in the case of booleans, being able to reuse state management logic is very nice.

## Decoupled state management, without the boilerplate

Most state management code is coupled to specific state. For example, in Redux or NgRx apps you will see state management like this:

```tsx
on(TodoActions.createSuccess, (state, { todo }) => ({
  ...state,
  todos: [...state.todos, todo],
  loading: false,
})),
```

The action `createSuccess` has specific event sources dispatching it, and this reducer is managing specific state. So all the state logic defined in this code is coupled to that specific state and that specific action, and it takes a fair amount of work to decouple it. 

Imagine if object-oriented programming didn't support the `new` key word. Every class you defined would actually be a specific object, not just some abstraction that could be used as over and over again with different data. How would people reuse any logic? They would define it _externally_, and import it into each class that needed it. But then the business logic isn't in the class anymore. The class turns into nothing more than a slab of boilerplate.

Does that sound familiar? This might remind you of reducers in Redux/NgRx. And extracting the logic into utilities is exactly what these libraries have done with their entity adapters. These provide some utilities for handling common state management patters, like this:

```tsx
on(TodoActions.createSuccess, (state, { todo }) =>
  adapter.addOne(todo, { ...state, loading: false })
),
```

But this only handles some of the logic; the remaining logic is still coupled to this specific reducer. 

What if we had an `asyncEntityAdapter`?

```tsx
on(TodoActions.createSuccess, (state, { todo }) =>
  adapter.addOneResolve(todo, state)
),
```

That's better. 

Now we just have the reducer boilerplate left. 

What if we just *always* wrote our state management logic inside adapters where it would be decoupled from any specific reducer? Our reducers would then only ever be calling adapter methods. And we could remove some boilerplate if the arguments of those adapter methods were switched and we could just reference the method:

```tsx
on(TodoActions.createSuccess, adapter.addOneResolve),
```

Now our reducer contains almost no boilerplate. If we want to get rid of all of it, we should be able to define our adapter code inside the reducer function itself, and only when needed, extract it by cutting and pasting the code to the outside where it can be used by multiple reducers. So the syntax for defining reducers and state adapters should be the same. But Redux and NgRx can't do this and don't provide any utilities for developers to easily define state adapter logic themselves, so we will look into some simple utilities we can provide ourselves later. 

First, let's explore state adapters themselves and other ways in which they might be valuable. 

## Composability

State is usually composed of smaller types/interfaces, like this:

```tsx
interface OptionState {
  value: string;
  checked: boolean;
}
```

In the first example above we saw that even a boolean state adapter could be valuable. And what if we also had a `stringAdapter`? And if we had those two, could we somehow define an `optionAdapter` that is composed of those two adapters, just as the `OptionState` interface is composed using the `string` and `boolean` types?

Let's say we have [a utility](https://state-adapt.github.io/concepts/adapters#createadapter) that allows us to define adapters with type inference. Our `booleanAdapter` could be defined like this:

```typescript
export const booleanAdapter = createAdapter<boolean>()({
  setTrue: () => true,
  setFalse: () => false,
  toggle: state => !state,
});
```

Imagine a similar definition for `stringAdapter`. 

Now how do we define an `optionAdapter` composed of these two adapters? We could just create a new adapter and use the child adapters directly:

```typescript
export const optionAdapter = createAdapter<Option>()({
  setValue: (state, value: string) => ({ ...state, value }),
  toggleChecked: state => ({
    ...state,
    checked: booleanAdapter.toggle(state.checked),
  }),
});
```

But `booleanAdapter.toggle(state.checked)` could have just been `!state.checked`. So this actually sucks.

So I came up with a function to make it easier to compose adapters:

```typescript
export const optionAdapter = joinAdapters<Option>()({
  value: baseStringAdapter,
  checked: booleanAdapter,
})();
```

That's all it takes, and in the end we get an object like this:

```typescript
{
  set: (state: Option, payload: Option) => payload,
  update: (state: Option, payload: Partial<Option>) => ({ ...state, ...payload }),
  reset: (s: Option, p: void, initialState: Option) => initialState,
  setValue: (state: Option, value: string) => ({ ...state, value }),
  resetValue: (state: Option, p: void, initialState: Option) => ({
    ...state,
    value: initialState.value,
  }),
  setChecked: (state: Option, checked: boolean) => ({ ...state, checked }),
  resetChecked: (state: Option, p: void, initialState: Option) => ({
    ...state,
    checked: initialState.checked,
  }),
  setCheckedTrue: (state: Option) => ({ ...state, checked: true }),
  setCheckedFalse: (state: Option) => ({ ...state, checked: false }),
  toggleChecked: (state: Option) => ({ ...state, checked: !state.checked }),
  selectors: {
    value: (state: Option) => state.value,
    checked: (state: Option) => state.checked,
  }
}
```

See how `booleanAdapter.setTrue` became `optionAdapter.setCheckedTrue`? `joinAdapters` assumes that each state change name will start with a verb. I thought about putting the namespace first, like `checkedToggle` and `checkedSetTrue`, but in some cases that gets confusing. Inserting the namespace after the first word is a small computational cost, but it makes the names clearer. And as of TypeScript 4.1, these types of string transformations are possible while keeping type inference intact. So it will warn you if you try to pass a payload into  `optionAdapter.setCheckedTrue` and it will make sure you pass a boolean into `optionAdapter.setChecked`. 

If state from multiple child adapters needs to change at the same time, `joinAdapters` has a way to let you define that so it happens efficiently. It also has a way to let you define memoized selectors that combine state from multiple child adapters. You can read more about these adapter patterns [here](https://state-adapt.github.io/concepts/adapters#joinadapters).

Between `createAdapter` and `joinAdapters` we can create and reuse some really sophisticated state patterns. 

## Adapter Creators

What if we want to create an adapter for some properties, but allow for consumers of our adapter to define extra properties on the state interface? What we need is a function like this:

```typescript
export function createOptionAdapter<T extends Option>() {
  return joinAdapters<T, Exclude<keyof T, keyof Option>>()({
    value: baseAdapter,
    checked: booleanAdapter,
  })();
}
```

This will create the same adapter as above, but it will also allow additional properties on the state object. So if you had an `Option` interface, it could have all the properties you wanted, as long as it also had `value` and `checked`. This is similar to how state shape can be extended with NgRx/Entity and Redux Toolkit. 

So, somebody could take the adapter returned from your function and combine it with their own adapter:

```typescript
interface Person {
  loading: boolean;
  value: string
  checked: boolean;
}

const optionAdapter = createOptionAdapter<Person>();

export const personAdapter = createAdapter<Person>()({
  receivePerson: (state, person: Person) => ({
    ...state,
    ...person,
    loading: false,
  }),
  ...optionAdapter,
  selectors: {
    loading: state => state.loading,
    ...optionAdapter.selectors,
  },
});
```

## An OP entity adapter

Most state management libraries that provide utilities for managing lists of entities give you all the basic tools, like `addOne`, `removeOne`, `setAll`, `removeMany`, etc...

But what if we assume that developers are going to be creating state adapters for the entities in the entity state? And what if they pass that adapter into our `createEntityAdapter` function? What could we do with that?

Normally an entity adapter will have state change functions called `updateOne` and `updateMany`. The entity adapter itself has no idea what update is being passed to it—just that it needs to spread it into the entity object. Here is an example I found:

```tsx
      return optionEntityAdapter.updateMany(
        state.ids.map((id: string) => ({
          id,
          changes: { selected: true },
        })),
        state,
      );
```

All of this work just to flip `selected` to `true` in every entity.

If we use the `booleanAdapter` to define an `optionAdapter`, and in turn use the `optionAdapter` to define the entity adapter, we could know that `setSelectedTrue` is a state change on `optionAdapter` and automatically generate a state change function that can be used like this:

```tsx
return optionEntityAdapter.setManySelectedTrue(state, state.ids);
```

For that matter, why not just give them an `All` variation for each state change function:

```tsx
return optionEntityAdapter.setAllSelectedTrue(state);
```

Think of all the state change functions we could define in an individual entity's adapter, and then `createEntityAdapter` can handle *all* the annoying list stuff!

### Filter selectors

What about filtering our entities? Well what if the `optionAdapter` had selectors that returned booleans? Couldn't we provide some entity selectors that used those to filter the entities?

Yes we can. I just used the same name as the filter, and it returns all entities for which `selected` is true.

What if we need to filter using multiple criteria? Just define it as another selector in the `optionAdapter`.

We can also use filter selectors to apply state changes selectively. Redux Toolkit and NgRx/Entity will have the `One`, `Many` and `All` ways of choosing which entities to change, but those are basically just filters. We can also create state change functions for each filter selector. 

So let's say we wanted to select all options that start with the letter `A`. The `optionAdapter` first needs a filter selector for this: 

```tsx
startsWithA: option => option.value.startsWith('A')`,
```

Now that becomes available on the `entityAdapter` like this: 
```tsx
entityAdapter.setStartsWithASelectedTrue
```

### Sorter selectors

If you define a selector that returns a value that can be compared with `>`, then it can also be used to sort the entities in a selector. The `optionAdapter` has a selector called `value` that returns a string, so we can use it to sort the entities in a selector called `entityAdapter.selectedByValue`, or `entityAdapter.allByValue`. 

### But should one?

This is extremely powerful. Potentially over-powered, and not in a good way. You might all be feeling like Jeff Goldblum right now.

![Jeff Goldblum Preoccupied Quote](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0oxuk1tfnbnu0pcmwdop.jpeg)

We already had a dozen or so state change functions in the `optionAdapter`, and that balloons to a ridiculous number when we feed it into `createEntityAdapter`. So, I added an options object that forces developers to specify which selectors to generate additional filter selectors and sort selectors for:

```tsx
const optionEntityAdapter = createEntityAdapter<Option>(optionAdapter, {
  filters: ['selected'],
  sorters: ['value'],
  useCache: true, // Selectors for each entity can be memoized if expensive
});
```

Even with this, `optionEntityAdapter` has around 100 state change functions to choose from. Honestly this is awesome, because TypeScript will filter the suggestions as you type and tell you what each does as you need it, none of which you needed to write. But what is the computational cost of this? Surprisingly, in my tests it only adds around a millisecond or two of computation time compared to creating a traditional entity adapter. This was something like 50% more time. So it's not going to slow the app down, but if it ever does, I can also look into making adapters proxy objects and defining these state change functions lazily. 

TypeScript is also doing a lot of work, but so far the type-checking is still very fast. I fine-tuned it a bit, but I'm not a TypeScript mastermind, so I'm sure it could still be optimized. 

But even with performance not being an issue, some of these names are just... awkward, aren't they? Any weird or ambiguous name in the individual entity adapter will get amplified in the entities adapter. 

But all of this saves so much code, and could really speed up development. So, with all the code that this saves, maybe it is worth it. 

Please feel free to try it out and give feedback!

## Conclusion

I'm really sick of writing code that looks like this: 

```tsx
({
  ...
  {
    ...
    {
      ...
    }
  }
})
```
or even dot-chaining with imperative code. Especially when it's the same exact code I've written dozens of times before! 

I don't expect state adapters to completely solve all of these issues. But UI components didn't solve all our issues either, did they? But they made UI development much simpler in the end, because you don't even have to think about whether the UI code you're writing needs to be reused, because it's already in a component by default! Why not write our state management code in the same way? And just like how component libraries were created, maybe state adapter libraries could be created too, or maybe shared alongside component libraries. Think of how much component libraries have sped up your work; maybe state adapters could do the same.

I don't know if state adapters are the ultimate solution to state management, but I am certain that they are better than coupling state management logic with reducers, and the syntax is much nicer. If you're hesitant about any of the composability stuff I talked about in this article, maybe you could just try using the simple `createAdapter` function and see how that goes.

Also, if you want a *really* nice experience managing state with state adapters, I would recommend you look into using the other [StateAdapt](https://state-adapt.github.io/) libraries. I have an RxJS library that hooks into Redux Devtools; you can see me using it in SolidJS and Svelte in [this video](https://www.youtube.com/watch?v=dnqj9fwdYAo&t=348s) (look at the timestamps). There's also an Angular library built on top of RxJS. And there's a React library too, although it could use some refining. 

StateAdapt 1.0 hasn't been released yet, so be aware that this isn't production ready. However, it's very close. After I've applied the entity adapter to a few projects, I will be releasing 1.0. 

Thanks for reading! Let me know what you think.