# 快速上手

ServiceX是一个**Typescript Project Only**的基于React hooks api之上的轻量级状态管理工具，主要的特点和解决的痛点有：

1. **灵活多store**：可以自由粒度的定义store，避免了redux在大项目中单一store越来越庞大的问题，并且提供一套强大的依赖注入功能来管理store
2. **严格ts类型**：项目本身有严格ts编写，同时对外接口处处都有TS类型推断，再也不用担心redux中action type拼错或者payload类型不兼容等隐形bug，同时更容易进行代码定位。
3. **强大的rxjs集成**：所有副作用都是通过rxjs进行描述和管理，与redux-saga相比，rxjs更通用，更强大，ts类型提示和约束做的更好。

### 安装

```
npm i service-x immer inversify reflect-metadata rxjs
```

### 使用

#### 开启ts中的编译flag:

编辑tsconfig.json中的complerOptions:

```javascript
{
  "compilerOptions": {
    "strict": true, // 严格模式，建议开启
    "emitDecoratorMetadata": true, // 开启metadata支持
    "experimentalDecorators": true,  // 开启decorator支持
    //...
  }
}

```

{% hint style="info" %}
experimentalDecorators虽然是实验性质的，但是这个flag已经稳定好几个版本了，大名鼎鼎的Angular也使用到了这个特性，所以不必担心之后的兼容问题。
{% endhint %}

#### 第一个Service

service代表了一个store，其中定义了store的state以及与redux概念相似的reducer， effect等action:

```typescript
// entry-service.ts
import {
  Injectable,
  Service,
  Reducer,
  ImmerReducer,
  Effect,
  EffectAction,
  DefineAction
} from "service-x";
import { Entry, fetchEntries } from "./fetch-entries";
import { Observable, merge } from "rxjs";
import {
  map,
  distinctUntilChanged,
  combineLatest,
  switchMap,
  debounceTime
} from "rxjs/operators";

interface State {
  entries: Entry[];
  keyword?: string;
}

@Injectable()
export class EntryService extends Service<State> {
  defaultState: State = {
    entries: []
  };
  // trigger loadEntries reload
  @DefineAction()
  reload$!: Observable<void>;

  @ImmerReducer()
  setKeyword(state: State, keyword: string) {
    state.keyword = keyword;
  }

  @ImmerReducer()
  setEntries(state: State, entries: Entry[]) {
    state.entries = entries;
  }

  @Reducer()
  reset(): State {
    return this.defaultState;
  }

  @Effect()
  loadEntries(
    trigger$: Observable<void>,
    state$: Observable<State>
  ): Observable<EffectAction> {
    const keyword$ = state$.pipe(
      map(state => state.keyword),
      distinctUntilChanged(),
      // debounce the input
      debounceTime(500)
    );

    return merge(trigger$, this.reload$).pipe(
      combineLatest(keyword$, (_, keyword) => keyword),
      switchMap(keyword => fetchEntries(keyword)),
      map(entries => this.actions().setEntries(entries))
    );
  }
}

```

#### 与React结合

```typescript
import React from "react";
import ReactDOM from "react-dom";
import { useService } from "service-x";
import { EntryService } from "./entry-service";
import "./index.less";

const App = () => {
  const [state, actions] = useService(EntryService, { resetOnUnmount: true });
  React.useEffect(() => {
    // load the entries on component mounted
    actions.loadEntries();
  }, [actions]);

  return (
    <>
      <input
        className="search"
        value={state.keyword}
        onChange={e => actions.setKeyword(e.target.value)}
        placeholder="Enter keywords to search"
      />
      {state.entries.length ? (
        <ul className="entries">
          {state.entries.map(entry => (
            <li className="entry" key={entry.name}>
              <span>{entry.name}</span>
              <small>{entry.age}</small>
            </li>
          ))}
        </ul>
      ) : (
        <p className="empty">Nothing found</p>
      )}
      <button onClick={() => actions.reload$()}>刷新</button>
    </>
  );
};

ReactDOM.render(<App />, document.getElementById("app"));
```

一个简单的人名搜索应用就OK啦，这里有一个更加高级的在线示例：

<https://codesandbox.io/s/service-x-demo-9dqw6>


---

# 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://xztech.gitbook.io/servicex/master.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.
