# usestore-ts

## [usestore-ts](https://github.com/seed2whale/usestore-ts?ref=morioh.com\&utm_source=morioh.com)

> 시드웨일에서 만든 전역 상태관리 도구&#x20;
>
> 지금까지 배운 decorator, metadata를 활용하는 것이 특징!

### Install

```
npm i usestore-ts
```

내부적으로 typescript decorator를 사용하므로 `tsconfig.json` 옵션들을 수정해주어야 한다.

```json
  "experimentalDecorators": true,
  "emitDecoratorMetadata": true,
```

### Usage

> 기존에 TSyringe + reflect-metadata를 사용하여 만든 간단한 스토어를 `usestore-ts` 를 사용하여 마이그레이션 해보자.

### CounterStore

> usestore-ts에서 제공하는 Store 데코레이터는 기존 ObjectStore 클래스를 대체한다.&#x20;
>
> 즉, ObjectStore가 제공하는 기능 (구독 관리, 상태변경을 알리는 작업 등)을 담고 있다는 것

```typescript
import { singleton } from 'tsyringe';
import { Store, Action } from 'usestore-ts';

/* 
 * 싱글톤 데코레이터를 스토어 데코레이터 보다 상위에 두자.
 * 싱글톤을 먹은 클래스를 스토어 데코레이터를 사용하면 이슈가 있을 수 있음
 */ 
@singleton()
@Store()
export default class CounterStore {
  counter = 0;
  // 액션 데코레이터는 publish 메서드를 머금고 있다.
  @Action()
  increase(step = 1) {
    this.counter += step;
  }

  @Action()
  decrease(step = 1) {
    this.counter -= step;
  }
}
```

### useCounterStore

> usestore-ts가 제공하는 useStore 훅으로 기존 useObjectStore를 대체
>
> forceUpdate 리스너를 머금고 있다.

```typescript
import { container } from 'tsyringe';
import { useStore } from 'usestore-ts';

import CounterStore from '../stores/counterStore';

export default function useCounterStore() {
  const store = container.resolve(CounterStore);

  return useStore(store);
}
```

### CounterController.tsx

> useStore(store)는 `[state, store]` 형태의 값을 반환한다.&#x20;
>
> state로 스토어에 담긴 값들을 사용
>
> store는 스토어에 담긴 액션 api들이 담겨 있다.

```tsx
import useCounterStore from '../hooks/useCounterStore';

export default function CounterController() {
  const [, store] = useCounterStore();

  const handleClickIncrease = (step?: number) => () => {
    store.increase(step);
  };

  const handleClickDecrease = (step?: number) => () => {
    store.decrease(step);
  };

  return (
    <div>
      <button type="button" onClick={handleClickIncrease(10)}>
        Increase 10
      </button>
      <button type="button" onClick={handleClickIncrease()}>
        Increase
      </button>
      <button type="button" onClick={handleClickDecrease(10)}>
        Decrease 10
      </button>
      <button type="button" onClick={handleClickDecrease()}>
        Decrease
      </button>
    </div>
  );
}
```

### Counter.tsx

```tsx
import useCounterStore from '../hooks/useCounterStore';

export default function Counter() {
  const [{ counter }] = useCounterStore();

  return (
    <div>
      <p>{`counter: ${counter}`}</p>
    </div>
  );
}
```

{% hint style="info" %}
[FECONF 2022 - 상태관리 이 전쟁을 끝내러 왔다](https://youtu.be/KEDUqA9JeIo)
{% endhint %}
