You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在React Query Builder中实现带路径输入框的自定义JSON字段?

问题描述

我正在使用React Query Builder开发,想要创建一个自定义字段:当选中的字段名称包含"JSON"字符串时,显示额外的文本框让用户输入PostgreSQL JSONB查询路径(如sub_obj_1->sub_obj_2),最终生成的查询规则需包含额外的path字段,示例格式如下:

{
  "field": "some json field",
  "path": "sub_obj_1->sub_obj_2",
  "operator": "=",
  "value": "val",
  "id": "268026e1-072b-4f64-8de4-8ebbbcb0a3f6"
}

当前使用的代码如下:

import { useState } from 'react';
import type { Field, RuleGroupType } from 'react-querybuilder';
import { QueryBuilder, formatQuery } from 'react-querybuilder';
import './styles.scss';

const fields: Field[] = [
  { name: 'firstName', label: 'First Name'},
  { name: 'lastName', label: 'Last Name' },
  {
    name: 'groupedField1',
    label: 'Grouped Field 1',
    comparator: 'groupNumber',
    groupNumber: 'group1',
    valueSources: ['field', 'value'],
  },
];

const initialQuery: RuleGroupType = {
  combinator: 'and',
  rules: [
    { field: 'firstName', operator: 'beginsWith', value: 'Stev' },
    { field: 'lastName', operator: 'in', value: 'Vai,Vaughan' },
    {
      field: "groupedField1",
      value: "groupedField1",
      operator: "=",
      valueSource: "field"
    },
  ],
};

export const App = () => {
  const [query, setQuery] = useState(initialQuery);

  return (
    <div>
      <QueryBuilder fields={fields} query={query} onQueryChange={setQuery} />

      <h4>Query</h4>
      <pre>
        <code>{formatQuery(query, 'json')}</code>
      </pre>
    </div>
  );
};
实现方案

要实现这个需求,需借助React Query Builder的自定义规则组件(ruleComponent)扩展字段UI,并在查询变更时维护path字段,具体步骤如下:

1. 扩展规则类型(TypeScript)

先扩展默认的RuleType,添加可选的path字段,确保类型检查通过:

import type { RuleType, RuleGroupType } from 'react-querybuilder';

// 扩展规则类型,新增path字段
type ExtendedRuleType = RuleType & {
  path?: string;
};

// 对应扩展分组类型
type ExtendedRuleGroupType = Omit<RuleGroupType, 'rules'> & {
  rules: Array<ExtendedRuleType | ExtendedRuleGroupType>;
};

2. 编写自定义规则组件

创建自定义规则组件,根据字段名称判断是否渲染路径输入框:

const CustomRule = ({ rule, updateRule, fields }: {
  rule: ExtendedRuleType;
  updateRule: (updates: Partial<ExtendedRuleType>) => void;
  fields: Field[];
}) => {
  const currentField = fields.find(f => f.name === rule.field);
  const showPathInput = currentField?.name.includes('JSON');

  return (
    <div style={{ display: 'flex', gap: '8px', alignItems: 'center', marginBottom: '8px' }}>
      {/* 字段选择器 */}
      <select
        value={rule.field}
        onChange={(e) => updateRule({ field: e.target.value, path: undefined })}
      >
        {fields.map(f => (
          <option key={f.name} value={f.name}>{f.label}</option>
        ))}
      </select>

      {/* 操作符选择器 */}
      <select
        value={rule.operator}
        onChange={(e) => updateRule({ operator: e.target.value })}
      >
        <option value="=">=</option>
        <option value="!=">!=</option>
        <option value="contains">Contains</option>
        {/* 可按需添加更多操作符 */}
      </select>

      {/* 值输入框 */}
      <input
        type="text"
        value={rule.value || ''}
        onChange={(e) => updateRule({ value: e.target.value })}
        placeholder="Enter value"
      />

      {/* JSON路径输入框(仅字段含JSON时显示) */}
      {showPathInput && (
        <input
          type="text"
          value={rule.path || ''}
          onChange={(e) => updateRule({ path: e.target.value })}
          placeholder="JSON Path (e.g. sub_obj_1->sub_obj_2)"
        />
      )}

      {/* NOT按钮与删除按钮 */}
      <button onClick={() => updateRule({ not: !rule.not })}>
        {rule.not ? '✓ NOT' : 'NOT'}
      </button>
      <button onClick={() => updateRule({ remove: true })}>×</button>
    </div>
  );
};

3. 更新App组件,使用自定义规则组件

修改App组件,替换默认规则组件,并调整状态类型:

export const App = () => {
  // 使用扩展后的类型定义查询状态
  const [query, setQuery] = useState<ExtendedRuleGroupType>(initialQuery as ExtendedRuleGroupType);

  return (
    <div>
      <QueryBuilder
        fields={fields}
        query={query}
        onQueryChange={setQuery as (q: RuleGroupType) => void}
        // 指定自定义规则组件
        ruleComponent={CustomRule}
      />

      <h4>Query</h4>
      <pre>
        <code>{formatQuery(query, 'json')}</code>
      </pre>
    </div>
  );
};

4. 添加JSON测试字段

在fields数组中添加包含"JSON"的字段,用于测试功能:

const fields: Field[] = [
  { name: 'firstName', label: 'First Name'},
  { name: 'lastName', label: 'Last Name' },
  {
    name: 'groupedField1',
    label: 'Grouped Field 1',
    comparator: 'groupNumber',
    groupNumber: 'group1',
    valueSources: ['field', 'value'],
  },
  // 添加JSON类型字段
  { name: 'userDataJSON', label: 'User Data (JSONB)' },
  { name: 'settingsJSON', label: 'Settings (JSONB)' },
];

关键说明

  • 自定义组件通过updateRule方法更新path字段,React Query Builder会自动将该字段纳入最终查询结构。
  • 切换字段时清空path,避免无效路径值残留。
  • 扩展类型是为了让TypeScript识别path字段,避免类型报错。

内容的提问来源于stack exchange,提问作者Mustafa Orkun Acar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 15:35:14