# 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 %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://taewoongs-organization.gitbook.io/jtwjs-dev-wiki/dev_road/week-6/usestore-ts.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
