React Native + Realm 离线方案处理

一、为什么选择 Realm?

  • 无需 SQL,直接用对象操作数据
  • 读写性能高,支持实时数据响应
  • 自带数据监听,数据变化 UI 自动刷新
  • 支持增量同步 / 增量下载,完美适配移动端离线业务
  • 跨平台(iOS/Android/React Native)一套代码通用

二、环境搭建

安装依赖 * Android 12+ / RN 0.71.3 / Realm 11.10.1

复制代码
# React Native 项目
npm install realm @realm/react

三、操作案例:

需求:

仓库作业系统,离线操作,

物料辅计量单位等基础信息内容存储在本地,

页面中操作查询的时候查询本地基础数据支持离线操作

1. 定义模型: 物料档案、计量单位等

复制代码
import Realm from 'realm';

// 实体模型
/**
 * 物料档案(MATERIAL)结构化存储
 * - primaryKey: code
 * 目标:可通过 code 快速取到 wholemanaflag / qualityunit 等字段
 */
export class Material extends Realm.Object<Material> {
    code!: string;
    pk_group!: string;
    pk_org!: string;
    pk_material!: string;
    pk_marbasclass!: string;

    name!: string;
    materialshortname!: string;
    materialtype!: string;
    materialbarcode!: string;
    materialspec!: string;
    graphid!: string;

    pk_measdoc!: string;
    pk_marasstframe!: string;

    wholemanaflag!: string;
    serialmanaflag!: string;
    islinecontrol!: string;
    sernumunit!: string;

    qualitymanflag!: string;
    qualitynum!: string;
    qualityunit!: string;

    version!: string;
    dr!: string;
    irownum!: string;

    def20!: string;
    def21!: string;
    def50!: string;

    bcolltype_1!: string;
    bcolltype_2!: string;
    bcolltype_3!: string;
    bcolltype_4!: string;
    bcolltype_5!: string;

    updatedAt!: Date;

    static schema: Realm.ObjectSchema = {
        name: 'Material',
        primaryKey: 'code',
        properties: {
            code: 'string',
            pk_group: 'string',
            pk_org: 'string',
            pk_material: 'string',
            pk_marbasclass: 'string',

            name: 'string',
            materialshortname: 'string',
            materialtype: 'string',
            materialbarcode: 'string',
            materialspec: 'string',
            graphid: 'string',

            pk_measdoc: 'string',
            pk_marasstframe: 'string',

            wholemanaflag: 'string',
            serialmanaflag: 'string',
            islinecontrol: 'string',
            sernumunit: 'string',

            qualitymanflag: 'string',
            qualitynum: 'string',
            qualityunit: 'string',

            version: 'string',
            dr: 'string',
            irownum: 'string',

            def20: 'string',
            def21: 'string',
            def50: 'string',

            bcolltype_1: 'string',
            bcolltype_2: 'string',
            bcolltype_3: 'string',
            bcolltype_4: 'string',
            bcolltype_5: 'string',

            updatedAt: 'date'
        }
    };
}

/**
 * 计量单位(MEASDOC)结构化存储
 * - primaryKey: pk_measdoc
 * 目标:
 * - 可通过 pk_measdoc 直接取 name / code / bitnumber 等字段
 * - 也允许通过 code 过滤查询到单位信息
 */
export class MeasDoc extends Realm.Object<MeasDoc> {
    pk_measdoc!: string;
    code!: string;
    name!: string;

    pk_group!: string;
    pk_org!: string;
    dr!: string;
    bitnumber!: string;
    irownum!: string;

    bcolltype_1!: string;
    bcolltype_2!: string;
    bcolltype_3!: string;
    bcolltype_4!: string;
    bcolltype_5!: string;

    updatedAt!: Date;

    static schema: Realm.ObjectSchema = {
        name: 'MeasDoc',
        primaryKey: 'pk_measdoc',
        properties: {
            pk_measdoc: 'string',
            code: 'string',
            name: 'string',

            pk_group: 'string',
            pk_org: 'string',
            dr: 'string',
            bitnumber: 'string',
            irownum: 'string',

            bcolltype_1: 'string',
            bcolltype_2: 'string',
            bcolltype_3: 'string',
            bcolltype_4: 'string',
            bcolltype_5: 'string',

            updatedAt: 'date'
        }
    };
}

2.增量下载逻辑

只拉取本地「最后更新时间」之后的新数据 / 变更数据,节省流量和性能。

javascript 复制代码
//下载下来数据allRows    下载时间 storedAt 
const r = upsertMaterial(realm, allRows, storedAt);
        
javascript 复制代码
/**
 * 写入 MATERIAL(结构化 upsert)
 * - 适合增量下载:只需要把本次返回的 rows upsert 进去即可
 */
export function upsertMaterial(
    realm: Realm,
    rows: any[],
    storedAt: Date
): { count: number; lastTime: string } {
    const updateMode: any = (Realm as any).UpdateMode?.Modified ?? 'modified';
    const safe = (v: any) => String(v ?? '');
    const list = Array.isArray(rows) ? rows : [];

    realm.write(() => {
        for (const r of list) {
            const code = safe(r?.code).trim();
            if (!code) continue;
            realm.create(
                'Material',
                {
                    code,
                    pk_group: safe(r?.pk_group),
                    pk_org: safe(r?.pk_org),
                    pk_material: safe(r?.pk_material),
                    pk_marbasclass: safe(r?.pk_marbasclass),

                    name: safe(r?.name),
                    materialshortname: safe(r?.materialshortname),
                    materialtype: safe(r?.materialtype),
                    materialbarcode: safe(r?.materialbarcode),
                    materialspec: safe(r?.materialspec),
                    graphid: safe(r?.graphid),

                    pk_measdoc: safe(r?.pk_measdoc),
                    pk_marasstframe: safe(r?.pk_marasstframe),

                    wholemanaflag: safe(r?.wholemanaflag),
                    serialmanaflag: safe(r?.serialmanaflag),
                    islinecontrol: safe(r?.islinecontrol),
                    sernumunit: safe(r?.sernumunit),

                    qualitymanflag: safe(r?.qualitymanflag),
                    qualitynum: safe(r?.qualitynum),
                    qualityunit: safe(r?.qualityunit),

                    version: safe(r?.version),
                    dr: safe(r?.dr),
                    irownum: safe(r?.irownum),

                    def20: safe(r?.def20),
                    def21: safe(r?.def21),
                    def50: safe(r?.def50),

                    bcolltype_1: safe(r?.bcolltype_1),
                    bcolltype_2: safe(r?.bcolltype_2),
                    bcolltype_3: safe(r?.bcolltype_3),
                    bcolltype_4: safe(r?.bcolltype_4),
                    bcolltype_5: safe(r?.bcolltype_5),

                    updatedAt: storedAt
                },
                updateMode
            );
        }
        const total = realm.objects<Material>('Material').length;
        upsertMeta(realm, 'MATERIAL', total, storedAt);
    });

    const meta = realm.objectForPrimaryKey<BaseDataMeta>('BaseDataMeta', 'MATERIAL');
    return {
        count: meta?.rowCount ?? realm.objects<Material>('Material').length ?? 0,
        lastTime: toTimeString(meta?.lastStoredAt ?? storedAt)
    };
}

realm.create() 第三个参数是 mode(写入模式)

用来控制当数据主键已存在时,应该怎么处理

3.模式 Realm 提供 3 种模式

1. Realm.UpdateMode.Never(默认)

  • 含义:不更新,只新增
  • 行为 :如果主键已存在,直接报错

2. Realm.UpdateMode.Modified(最常用!)

  • 含义存在则更新,不存在则新增(upsert)
  • 行为 :根据主键匹配
    • 有这条数据 → 只更新变化的字段
    • 没有这条数据 → 直接新增

3. Realm.UpdateMode.All

  • 含义:全量覆盖
  • 行为 :如果数据存在,直接用新对象覆盖整个对象
  • 所有 写操作(增 / 删 / 改) 必须放在realm.write(() => { ... }) 里面

  • 单条操作靠 主键定位

四、常用操作:

1.查询单条:
javascript 复制代码
const item = realm.objectForPrimaryKey('Material', code);
2. 新增单条
javascript 复制代码
// 新增
realm.write(() => {
  realm.create('Material', {
    id: Date.now(),       // 唯一主键
    name: '原料仓库',    // 字段
    address: '上海',
    stock: 100,
    updateTime: new Date()
  });
});
3. 修改单条(最常用)
javascript 复制代码
realm.write(() => {
  // 1. 找到要修改的那一条
  const item = realm.objectForPrimaryKey('Material', 123);

  if (item) {
    // 2. 直接改字段
    item.name = '修改后的仓库名';
    item.stock = 200;
    item.updateTime = new Date();
  }
});

realm.write(() => {
  realm.create(
    'Material',
    {
      id: 123,          // 必须传主键
      name: '新名称',
      stock: 200
    },
    Realm.UpdateMode.Modified // 有则更新,无则新增
  );
});
4. 删除单条
javascript 复制代码
realm.write(() => {
  // 1. 找到要删的那一条
  const item = realm.objectForPrimaryKey('Material', 123);

  if (item) {
    // 2. 删除
    realm.delete(item);
  }
});
相关推荐
傻小胖3 小时前
Object.defineProperty() 完整指南
开发语言·前端·javascript
hong1616883 小时前
TypeScript类型断言
linux·javascript·typescript
BUG_Jia3 小时前
Vue 3 组件封装与使用:保姆级教程
前端·javascript·vue.js
思成Codes3 小时前
从本质看:Vue3 为什么运用 LIS 算法
javascript·vue.js
江湖行骗老中医4 小时前
Pinia 是 Vue 的专属状态管理库
前端·javascript·vue.js
张元清4 小时前
React 鼠标追踪与交互效果实战
前端·javascript·面试
kyriewen4 小时前
你的JS代码总在半夜崩溃?TypeScript来“上保险”了
前端·javascript·typescript
iReachers4 小时前
HTML打包EXE配置管理教程:多项目打包设置一键保存、加载与切换
java·前端·javascript