# @fresha/fresha-redux-orm 中文文档

规范地址：https://npmcn.com/package/%40fresha/fresha-redux-orm/

版本：0\.1\.19
npm 元数据更新时间：2023-03-28T13:54:04.032Z
中文译文更新时间：2026-11-15T13:50:02.497Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40fresha/fresha-redux-orm
原文对照：https://npmcn.com/package/%40fresha/fresha-redux-orm/?lang=original
项目主页：https://github.com/surgeventures/noname#readme
源码仓库：https://github.com/surgeventures/noname

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：1.4 MB，163 个文件
- 模块格式：CommonJS
- TypeScript 类型：未声明
- 运行依赖：4 个
- 首次发布：2021-10-21T14:38:11.273Z
- 最新版本发布：2022-05-27T11:21:04.997Z
- 近 30 天下载量：26604（2026-10-16 至 2026-11-14，npm 官方下载统计）
- 已发布版本数：15（近 12 个月 0 个）

## 中文简介

简单的 ORM 管理和查询您的状态树

## 安装

```sh
npm install @fresha/fresha-redux-orm
```

也可以使用：`pnpm add @fresha/fresha-redux-orm`、`yarn add @fresha/fresha-redux-orm`、`bun add @fresha/fresha-redux-orm`

## README

# Redux - ORM 软件

[![Build Status](https://img.shields.io/travis/tommikaikkonen/redux-orm.svg?style=flat-square)](https://travis-ci.org/tommikaikkonen/redux-orm) [![Codacy Grade](https://img.shields.io/codacy/grade/55fea9be60974a5c9b8f0459070dfefc.svg?style=flat-square)](https://www.codacy.com/app/haveyaseen/redux-orm?utm_source=github.com&utm_medium=referral&utm_content=tommikaikkonen/redux-orm&utm_campaign=Badge_Grade) [![Coverage Status](https://img.shields.io/codecov/c/github/tommikaikkonen/redux-orm/master.svg?style=flat-square)](https://codecov.io/gh/tommikaikkonen/redux-orm/branch/master) [![NPM package](https://img.shields.io/npm/v/redux-orm.svg?style=flat-square)](https://www.npmjs.com/package/redux-orm) ![GitHub Release Date](https://img.shields.io/github/release-date/tommikaikkonen/redux-orm.svg?style=flat-square) [![NPM downloads](https://img.shields.io/npm/dm/redux-orm.svg?style=flat-square)](https://www.npmjs.com/package/redux-orm) [![Gitter](https://badges.gitter.im/redux-orm/Lobby.svg?style=flat-square)](https://gitter.im/redux-orm/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) ![NPM license](https://img.shields.io/npm/l/redux-orm.svg?style=flat-square)

见 [使用 Redux- ORM 创建简单应用程序的指南](https://github.com/tommikaikkonen/redux-orm-primer) (包括来源). 其README尚未更新为0.9,但 [代码有它的分支](https://github.com/tommikaikkonen/redux-orm-primer/tree/migrate_to_0_9)。 。 。 .

**0.9.x版本为API带来了很大的突破变化. 请看 [移徙指南](https://github.com/tommikaikkonen/redux-orm/wiki/0.9-Migration-Guide) 如果你是从早期的版本迁移过来的.**

找0.8个医生? 读取 [重播中的旧读取器](https://github.com/tommikaikkonen/redux-orm/tree/3c36fa804d2810b2aaaad89ff1d99534b847ea35). 对于 API 的参考文献,克隆 repo, `npm install`, (中文(简体) ), `make build` 打开 `index.html` 在您的浏览器中。 抱歉给您带来不便.

API可以不稳定到1.0. 在 1. 0. 0 之前的小版本会起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起起 将在本报告中予以说明 [更改日志](https://github.com/tommikaikkonen/redux-orm/blob/master/CHANGELOG.md)。 。 。 .

## 安装

```bash
npm install redux-orm --save
```

或带有脚本标签

```html
<script src="https://tommikaikkonen.github.io/redux-orm/dist/redux-orm.min.js"></script>
```

-   [浏览器按主机构建](https://tommikaikkonen.github.io/redux-orm/dist/redux-orm.js)
-   [浏览器按照主机构建( 最小化)](https://tommikaikkonen.github.io/redux-orm/dist/redux-orm.min.js)

### 多元填充

Redux-ORM使用一些ES2015+特性,例如: `Set`。如果在 ES2015+ 之前的环境中使用 Redux- ORM ,您应该装入像 ES2015+ 那样的多填充 [`babel-polyfill`](https://babeljs.io/docs/usage/polyfill/) 在使用Redux-ORM之前.

### 扩展

-   [`redux-orm-proptypes`](https://github.com/tommikaikkonen/redux-orm-proptypes): React PropTypes 验证和 Redux-ORM 模型的默认Props 混用

## 使用量

### 宣布您的模式

您可以使用 ES6 类语法来声明您的模型, 扩展为 `Model`。您需要在模型上声明您的全部非关系字段,并且推荐所有数据字段,因为库在即时模型时不需要重新定义获取器和设置器。 Redux-ORM除了外国密钥外,还支持一对一和多对多的关系(`oneToOne`, (中文(简体) ), `many` 财务报告和审定财务报表 `fk` (分别为进口)。 非相干属性可以和普通JavaScript对象一样被访问.

```javascript
// models.js
import {fk, many, attr, Model} from 'redux-orm';

class Book extends Model {
    toString() {
        return `Book: ${this.name}`;
    }
    // Declare any static or instance methods you need.
}
Book.modelName = 'Book';

// Declare your related fields.
Book.fields = {
    id: attr(), // non-relational field for any value; optional but highly recommended
    name: attr(),
    authors: many('Author', 'books'),
    publisher: fk('Publisher', 'books'),
};

export default Book;
```

### 注册模式并生成一个空数据库状态

在模型上定义字段,规定了该模型数据库中的表格结构。 为了生成整个数据库结构的描述,我们需要一个中心位置来注册我们想要使用的所有模型.

ORM类的一个实例是登记模型,处理从所有模型中生成一个完整的计划,并将这些信息传送到数据库。 您通常想要有一个文件, 可以在应用程序上导入一个 ORM 实例, 像这样 :

```javascript
// orm.js
import { ORM } from 'redux-orm';
import { Book, Author, Publisher } from './models';

const orm = new ORM();
orm.register(Book, Author, Publisher);

export default orm;
```

您也可以定义 _财务报告和审定财务报表_ 将模型注册到同一文件中的 ORM 实例,并全部导出.

现在我们已经注册了模型, 我们可以生成一个空的数据库状态。 目前,这是一个平地,嵌入式的JavaScript对象,其结构类似于关系数据库.

```javascript
// index.js

import orm from './orm';

const emptyDBState = orm.getEmptyState();
```

### 将更新应用到数据库

当我们有数据库状态时,我们可以开始一个关于此的ORM会话来应用更新. ORM实例提供了一个 `session` 用于接受数据库状态作为唯一参数的方法,并返回会话实例.

```javascript
const session = orm.session(emptyDBState);
```

特定会话分类的已注册模型作为会话对象的属性可供使用.

```javascript
const Book = session.Book;
```

模型提供了查询和更新数据库状态的接口.

```javascript
Book.withId(1).update({ name: 'Clean Code' });
Book.all().filter(book => book.name === 'Clean Code').delete();
Book.idExists(1)
// false
```

初始数据库状态没有变异. 可在 `state` 属性.

```javascript
const updatedDBState = session.state;
```

## Redux 整合

要将 Redux-ORM 与 Redux 整合到最基本的级别,您可以定义一个从 Redux 原子上所持有的数据库状态中即时生成一个会话的还原器,然后,当您应用了所有更新时,您就可以从会话中返回下一个状态.

```javascript
import orm from './orm';

function ormReducer(dbState, action) {
    const sess = orm.session(dbState);

    // Session-specific Models are available
    // as properties on the Session instance.
    const { Book } = sess;

    switch (action.type) {
    case 'CREATE_BOOK':
        Book.create(action.payload);
        break;
    case 'UPDATE_BOOK':
        Book.withId(action.payload.id).update(action.payload);
        break;
    case 'REMOVE_BOOK':
        Book.withId(action.payload.id).delete();
        break;
    case 'ADD_AUTHOR_TO_BOOK':
        Book.withId(action.payload.bookId).authors.add(action.payload.author);
        break;
    case 'REMOVE_AUTHOR_FROM_BOOK':
        Book.withId(action.payload.bookId).authors.remove(action.payload.authorId);
        break;
    case 'ASSIGN_PUBLISHER':
        Book.withId(action.payload.bookId).publisher = action.payload.publisherId;
        break;
    }

    // the state property of Session always points to the current database.
    // Updates don't mutate the original state, so this reference is not
    // equal to `dbState` that was an argument to this reducer.
    return sess.state;
}
```

之前Redux-ORM主张通过附加静态来减少模型特有的还原器 `reducer` 函数。 如果您要在模型类中定义更新逻辑, 您可以指定一个 `reducer` 在您的模型上采用静态方法,将动作作为第一个参数,会话特定模型作为第二个参数,整个会话作为第三个参数.

```javascript
class Book extends Model {
    static reducer(action, Book, session) {
        switch (action.type) {
        case 'CREATE_BOOK':
            Book.create(action.payload);
            break;
        case 'UPDATE_BOOK':
            Book.withId(action.payload.id).update(action.payload);
            break;
        case 'REMOVE_BOOK':
            const book = Book.withId(action.payload);
            book.delete();
            break;
        case 'ADD_AUTHOR_TO_BOOK':
            Book.withId(action.payload.bookId).authors.add(action.payload.author);
            break;
        case 'REMOVE_AUTHOR_FROM_BOOK':
            Book.withId(action.payload.bookId).authors.remove(action.payload.authorId);
            break;
        case 'ASSIGN_PUBLISHER':
            Book.withId(action.payload.bookId).publisher = action.payload.publisherId;
            break;
        }
        // Return value is ignored.
        return undefined;
    }

    toString() {
        return `Book: ${this.name}`;
    }
}
```

要为Redux获得一个调用这些的简化器 `reducer` 方法:

```javascript
import { createReducer } from 'redux-orm';
import orm from './orm';

const reducer = createReducer(orm);
```

`createReducer` 很简单,所以我就贴上源头.

```javascript
function createReducer(orm, updater = defaultUpdater) {
    return (state, action) => {
        const session = orm.session(state || orm.getEmptyState());
        updater(session, action);
        return session.state;
    };
}

function defaultUpdater(session, action) {
    session.sessionBoundModels.forEach(modelClass => {
        if (typeof modelClass.reducer === 'function') {
            modelClass.reducer(action, modelClass, session);
        }
    });
}
```

如你所见,它只是即兴地播放了一个新会话,循环了会话中的所有模型,并称为 `reducer` 方法,如果它存在。 然后它返回所有应用更新的新数据库状态.

### 用反应

使用被纪念的选择器对状态进行查询. Redux-ORM使用智能记忆:以下选择器访问 `Author` 财务报告和审定财务报表 `AuthorBooks` 分支`AuthorBooks` 是一个从模型字段声明生成的从多到多的分支,只有在这些分支发生变化时,选择者才会重新计算。 进入的分行在第一次运行时解决.

```javascript
// selectors.js
import { createSelector } from 'redux-orm';
import orm from './orm';

const dbStateSelector = state => state.db;

const authorSelector = createSelector(
    orm,
    // The first input selector should always select the db-state.
    // Behind the scenes, `createSelector` begins a Redux-ORM session
    // with the value returned by `dbStateSelector` and passes
    // that Session instance as an argument instead.
    dbStateSelector,
    session => {
        return session.Author.all().toModelArray().map(author => {

            // Returns a reference to the raw object in the store,
            // so it doesn't include any reverse or m2m fields.
            const obj = author.ref;
            // Object.keys(obj) === ['id', 'name']

            return Object.assign({}, obj, {
                books: author.books.toRefArray().map(book => book.name),
            });
        });
    }
);

// Will result in something like this when run:
// [
//   {
//     id: 0,
//     name: 'Tommi Kaikkonen',
//     books: ['Introduction to Redux-ORM', 'Developing Redux applications'],
//   },
//   {
//     id: 1,
//     name: 'John Doe',
//     books: ['John Doe: an Autobiography']
//   }
// ]
```

选择器创建 `createSelector` 可用作任何额外的输入 `reselect` 选择要使用的选项。 也有很多东西可以使用 `redux-thunk`: 使整个州与 `getState()`,将ORM分支传递给选择器,并获取结果。 一个很好的用法案例是将数据序列化为第三方API呼叫的自定义格式.

因为选取者被回忆,所以可以在React中使用纯渲染来获得性能收益.

```jsx
// components.js
import React from 'react';
import { authorSelector } from './selectors';
import { connect } from 'react-redux';

class App extends React.PureComponent {
    render() {
        const authors = this.props.authors.map(author => {
            return (
                <li key={author.id}>
                    {author.name} has written {author.books.join(', ')}
                </li>
            );
        });

        return (
            <ul>
                {authors}
            </ul>
        );
    }
}

function mapStateToProps(state) {
    return {
        authors: authorSelector(state),
    };
}

export default connect(mapStateToProps)(App);
```

## 理解Redux-ORM

### 手术室?

对 Redux-ORM处理相关数据,结构类似于关系数据库. 此情况下的数据库是一个简单的JavaScript对象数据库.

### 为什么?

对于简单的应用程序来说,手写还原器是好的,但是当对象类型数量增加,需要保持它们之间的关系时,事物会变得毛发. ImmustableJS在降低你的还原器的复杂度方面有很长的路要走,但Redux-ORM是专用于关系数据的.

### 可变性

我们从一个位于Redux原子的初始数据库状态开始一个会话,更新某一本书的名称.

第一,新会议:

```javascript
import { orm } from './models';

const dbState = getState().db; // getState() returns the redux state.
const sess = orm.session(dbState);
```

会话保持数据库状态的引用. 我们没有 更新数据库状态,因此它仍然等于原始状态 状态.

```javascript
sess.state === dbState
// true
```

让我们应用更新.

```javascript
const book = sess.Book.withId(1)

book.name // 'Refactoring'
book.name = 'Clean Code'
book.name // 'Clean Code'

sess.state === dbState
// false.
```

应用了更新,由于会话没有变换出原始状态,它创建了一个新的状态并互换了 `sess.state` 来指向新的一个.

让我们通过ORM再次更新数据库状态.

```javascript

// Save this reference so we can compare.
const updatedState = sess.state;

book.name = 'Patterns of Enterprise Application Architecture'

sess.state === updatedState
// true. If possible, future updates are applied with mutations. If you want
// to avoid making mutations to a session state, take the session state
// and start a new session with that state.
```

如果可能的话,未来更新会随着突变而应用. 在这种情况下,数据库已经变了,所以指针不需要改变. 如果您想要避免变换到会话状态, 请选择会话状态, 并以此状态开始新的会话 .

### 自定义

就像你可以延长 `Model`你也可以为 `QuerySet` (关于模型实例集的定制方法). 您也可以自行指定整个数据库的执行(待发文档) .

### 洞穴

![gzip size](https://img.shields.io/bundlephobia/minzip/redux-orm.svg?style=flat-square)

ORM抽象将永远不会像手写还原器那样表现,并且会增加您的项目的构建大小. 如果数据非常简单,没有关系,Redux-ORM可能会过度杀伤. 然而,发展便利的好处相当可观.

## API 密码

### 机构

见ORM的全部文档 [这里](http://tommikaikkonen.github.io/redux-orm/global.html#ORM)

证据

```javascript
const orm = new ORM(); // no arguments needed.
```

实例方法 :

-   `register(...models: Array<Model>)`: 将模型类登记到 `ORM` 举个例子.
-   `session(state: any)`: 开始一个新的 `Session` 与 `state`。 。 。 .

### Redux 整合

-   `createReducer(orm: ORM)`:返回一个可以被插入Redux的还原器函数. 减少器会返回数据库的下个状态, 前提是已提供动作 。 在打电话之前,你需要登记你的模型.
-   `createSelector(orm: ORM, [...inputSelectors], selectorFunc)`: 返回用于 `selectorFunc`。 。 。 . `selectorFunc` 接收 `session` 作为第一个论据,然后是来自 `inputSelectors`。请注意,第一个输入选择器必须返回 db 状态才能创建会话。 详细阅读文件全文.

### 型号

见文件全文 `Model` [这里](http://tommikaikkonen.github.io/redux-orm/Model.html)。 。 。 .

**证据**: 不直接即时; 使用类方法 `create` 财务报告和审定财务报表 `upsert` 载于下文.

**分类方法**数字 :

-   `withId(id)`: 获得 id 的模型实例 `id`。 。 。 .
-   `idExists(id)`: 返回布尔表示一个有 id 的实体 `id` 在州内存在.
-   `exists(matchObj)`: 返回布尔表示属性匹配的实体 `matchObj` 在州内存在.
-   `get(matchObj)`: 获得基于匹配属性的模型实例 `matchObj` (如果你确定只有一个匹配实例).
-   `create(props)`: 创建一个新的模型实例 `props`如果你不提供身份证明,新的 `id` 将会是 `Math.max(...allOtherIds) + 1`。 。 。 .
-   `upsert(props)`: 要么创建新的模型实例 `props` 或者,如果一个有相同身份证明的例子已经存在, 更新一个 -换句话说,它是 **创建或更新** 行为.

你几乎可以接触到所有 [查询集实例方法](http://tommikaikkonen.github.io/redux-orm/QuerySet.html) 为方便而从类对象中选出,包括 `where` 和类似.

**实例属性**数字 :

-   `ref`: 返回直接引用代表商店中模型实例的平版JavaScript对象.

**实例方法**数字 :

-   `equals(otherModel)`: 返回布尔表示平等 `otherModel`平等是由对两种模式的属性进行浅析比较所决定的.
-   `set(propertyName, value)`: 更新 `propertyName` 改为 `value`. 回归 `undefined`。相当于正常任务.
-   `update(mergeObj)`: 合并 `mergeObj` 带有模型实例属性。 回返 `undefined`。 。 。 .
-   `delete()`:删除数据库中该模型实例的记录。 回返 `undefined`。 。 。 .

**子分类**数字 :

使用 ES6 语法到子类 `Model`。您宣布的任何实例方法都将在模型实例中提供。 您声明的任何静态方法都会在会话的模型类中可用.

有关领域的申报,无论是确定 `fields` 属性或声明返回此字段声明的静态获取器:

**声明 `fields`**数字 :

```javascript
class Book extends Model {
    static get fields() {
        return {
            id: attr(),
            name: attr(),
            author: fk('Author'),
        };
    }
}
// alternative:
Book.fields = {
    id: attr(),
    name: attr(),
    author: fk('Author'),
}
```

所有田园 `fk`, (中文(简体) ), `oneToOne` 财务报告和审定财务报表 `many` 仅取一个参数,相关的模型名称。 每个字段都有属性 `Model` 举个例子 您可以设置相关字段, 包含相关实例的 id 值, 或相关实例本身 .

对于 `fk`,您可以通过 `author.bookSet`,在相关名称的位置 `${modelName}Set`。同样的 `many`用于 `oneToOne`,反向关系可以仅通过该字段被声明的模型名称访问: `author.book`。 。 。 .

对于 `many` 字段声明,在模型实例中访问字段将返回 a `QuerySet` 另有两种方法: `add` 财务报告和审定财务报表 `remove`。它们需要1个或更多个参数,这些参数要么是模型实例,要么是其ID。 调用这些方法记录将在下一个状态中反映的更新.

当宣布模范课时,总是记得设置 `modelName` 属性。 它需要被明确设定, 因为运行您的代码通过 mangler 否则会打破功能 。 这个 `modelName` 将用来解决所有相关领域.

**声明 `modelName`**数字 :

```javascript
class Book extends Model {
    static get modelName() {
        return 'Book';
    }
}
// alternative:
Book.modelName = 'Book';
```

**声明 `options`**

如果您需要向 Redux- ORM 数据库指定选项, 您可以声明静态 `options` 带有对象键的模型类属性。 目前您可以指定 id 属性名称 :

```javascript
// This is the default value. 
Book.options = {
    idAttribute: 'id',
};
```

### 查询

见文件全文 `QuerySet` [这里](http://tommikaikkonen.github.io/redux-orm/QuerySet.html)。 。 。 .

你可以直接从一个 `Model` 类,好像它们 是类方法 `Model`。在这种情况下,这些功能将在包含所有模型实例的查询组上运行.

**实例方法**数字 :

-   `toRefArray()`: 返回以 `QuerySet` 作为平版JavaScript对象的阵列. 物体是直接引用商店的.
-   `toModelArray()`: 返回以 `QuerySet` 作为数组 `Model` 实例对象.
-   `count()`: 返回编号 `Model` 实例 `QuerySet`。 。 。 .
-   `exists()`: 回转 `true` 如果实体数超过 0,则另 `false`。 。 。 .
-   `filter(filterArg)`: 返回一个新的 `QuerySet` 代表通过过滤器的父查询程序的记录。 对于 `filterArg`,您可以通过Redux-ORM试图与实体匹配的对象,也可以通过返回的函数 `true` 如果你想在新的里面拥有它 `QuerySet`, (中文(简体) ), `false` 如果不是的话。 该函数收到一个模型实例作为它唯一的论据.
-   `exclude` 返回一个新的 `QuerySet` 重置在母目录中不通过过滤器的实体 。 与 `filter`,您可以通过一个对象进行匹配(所有匹配的实体将不会在新的 `QuerySet`)或函数。 该函数收到一个模型实例作为它唯一的论据.
-   `all()` 返回一个新的 `QuerySet` 与同样的实体.
-   `at(index)` 返回一个 `Model` 实例 `index` 输入 `QuerySet`。 。 。 .
-   `first()` 返回一个 `Model` 实例 `0` 指数.
-   `last()` 返回一个 `Model` 实例 `querySet.count() - 1` 指数.
-   `delete()` 删除以 `QuerySet`。 。 。 .
-   `update(mergeObj)` 更新以 `QuerySet` 基于所提供对象。 该对象将与每个实体合并.

### 会议

见会议的全部文件 [这里](http://tommikaikkonen.github.io/redux-orm/Session.html)

**证据**:你不需要自己做到这一点。 使用 `orm.session`。 。 。 .

**实例属性**数字 :

-   `state`: 当前数据库状态.

此外, 您可以访问计划中所有注册的模型, 作为此实例的属性进行查询和更新 。 举例来说,给定一个与 `Book` 财务报告和审定财务报表 `Author` 型号,

```javascript
const session = orm.session(state);
session.Book // Model class: Book
session.Author // Model class: Author
session.Book.create({id: 5, name: 'Refactoring', release_year: 1999});
```

## 更改日志

V1.0.0 之前的细微更改可以包括断开更改.

见 [`CHANGELOG.md`](https://github.com/tommikaikkonen/redux-orm/blob/master/CHANGELOG.md)。 。 。 .

## 许可证

麻省理工学院. 见 [`LICENSE`](https://github.com/tommikaikkonen/redux-orm/blob/master/LICENSE)。 。 。 .

## 常见问题

### @fresha/fresha-redux-orm 是什么？

简单的 ORM 管理和查询您的状态树

### 如何安装 @fresha/fresha-redux-orm？

在项目目录运行 npm install @fresha/fresha-redux-orm，或使用 pnpm add / yarn add / bun add。

### @fresha/fresha-redux-orm 支持 TypeScript 吗？

该包的 package\.json 没有声明类型入口。需要类型提示时，可以在 npm 上查找社区维护的 @types/fresha\_\_fresha-redux-orm 是否存在。

### @fresha/fresha-redux-orm 支持 ESM 还是 CommonJS？

以 CommonJS 形式发布，可以直接 require\(\)；在 ES Module 项目中也可以用 import 引入（Node\.js 会把 module\.exports 作为默认导出）。

### @fresha/fresha-redux-orm 可以商用吗？

@fresha/fresha-redux-orm 使用 MIT 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### @fresha/fresha-redux-orm 的下载量有多少？

根据 npm 官方下载统计，@fresha/fresha-redux-orm 在 2026/10/16 – 2026/11/14 这 30 天内被下载 26,604 次，日均约 887 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @fresha/fresha-redux-orm 还在维护吗？

最新版本 0\.1\.19 发布于 2022/05/27（4 年前）；至今共发布 15 个版本，其中过去 12 个月发布了 0 个；首次发布于 2021/10/21。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

