---
sidebar_position: 1
title: 快速上手
---

:::caution
新项目不再推荐使用 Reduck，可以使用社区中的状态管理工具，例如 [Jotai](https://jotai.org/)、[zustand](https://zustand.docs.pmnd.rs/getting-started/introduction)、[valtio](https://valtio.dev/docs/introduction/getting-started) 等。
:::

# 快速上手

import ReduckMigration from "@site-docs/components/reduck-migration"

<ReduckMigration />

[Reduck](https://github.com/web-infra-dev/reduck) 是 Modern.js 团队开发的遵循 MVC 模式的状态管理库，底层状态存储基于 [Redux](https://redux.js.org/) 实现，同时提供更高层级的抽象，并完全兼容 Redux 生态。

Reduck 的目标是以 MVC 模式组织 React 应用开发结构，将业务逻辑维护在 Model 层，业务逻辑与 UI 解耦，让开发业务逻辑更集中、更简单，同时通过更高层级的抽象，减少重复工作（样板代码）。

Reduck 在 MVC 模式中，扮演 M(Model) 的角色，React UI Component 对应 V(View)，从 Reduck 中获取 Model 并修改 Model 的 React Container Component 对应 C(View Controller/Container)。

Modern.js 的状态管理解决方案，是通过内置 Reduck 实现的。在 Modern.js 中使用 Reduck，不仅免去了手动集成的环节，而且所有 Reduck API 都可以从 Modern.js 的 Runtime 包中直接导入使用，具有更好的一致性体验。

:::info
1. Modern.js 中使用 Reduck API，需要先设置 [runtime.state](/configure/app/runtime/state) 以启用状态管理插件。
2. Reduck 也可以脱离 Modern.js 作为状态管理库[单独使用](/guides/topic-detail/model/use-out-of-modernjs)。

:::

## 核心概念

Reduck 中的核心概念只有 4 个： Model、State、Actions、Effects。

Model: 对独立模块的逻辑和所需状态的封装，由 State、Actions、Effects 组成。

State: Model 中保存的状态。

Actions: 用于修改 State 的纯函数，函数必须是**同步**的。

Effects: 用于修改 State 的带有副作用的函数，函数可以是**异步**的。Effects 中可以调用自身或其他 Model 的 Actions 和 Effects。

Reduck 数据流如下图所示：

![Reduck 数据流](https://lf3-static.bytednsdoc.com/obj/eden-cn/zq-uylkvT/ljhwZthlaukjlkulzlp/reduck-concept.svg)

## 基本用法

下来我们以一个简单的 **计数器** 应用为例，演示 Reduck 的基本用法。

首先，我们定义一个名为 `count` 的 Model：

```js
import { model } from '@modern-js/runtime/model';

const countModel = model('count').define({
  state: {
    value: 1,
  },
});

export default countModel;
```

我们使用 API `model` 创建 `countModel`，`countModel` 当前只包含存储计数器值的状态，即代码中的 `value`。

我们定义一个 action，用于计算器自增加 1：

```js
import { model } from '@modern-js/runtime/model';

const countModel = model('count').define({
  state: {
    value: 1,
  },
  actions: {
    add(state) {
      state.value += 1;
    },
  },
});

export default countModel;
```

在 `add` action 中，我们可以直接修改 state 的值，进行加 1 操作，而不需要把 state 作为不可变对象进行操作，这是因为 Reduck 集成了 [immer](https://github.com/immerjs/immer)，可以直接修改原 state 对象。

接下来，我们演示如何在组件中使用 Model。

新建一个组件 Counter，在组件内通过 `useModel` API 使用 `countModel`：

```js
import { useModel } from '@modern-js/runtime/model';
import countModel from './models/count';

function Counter() {
  const [state, actions] = useModel(countModel);

  return (
    <div>
      <div>counter: {state.value}</div>
      <button onClick={() => actions.add()}>add</button>
    </div>
  );
}
```

`useModel` 获取 `countModel` 的 `state` 和 `actions`，组件展示当前计算器的值，点击 `add` 按钮，计数器自增 1。

:::info
由于使用的案例比较简单，这里并没有严格按照 MVC 模式进行分层，组件 `Counter` 同时起到了 V 和 C 两层的作用。

:::

最终演示效果如下：

![countModel](https://lf3-static.bytednsdoc.com/obj/eden-cn/eueh7vhojuh/modern/simple-count-model.gif)

这样，我们就完了一个简单的计数器应用。本节完整的示例代码可以在[这里](https://github.com/web-infra-dev/modern-js-examples/tree/main/examples/runtime-api/counter-model)查看。
