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

如何在urql-react中集中序列化Date与DateTime类型?

在urql-react中集中处理Date/DateTime标量序列化

要实现集中处理Date和DateTime标量的序列化,核心是利用urql的mapExchange拦截 outgoing 请求,统一格式化变量中的日期类型,无需在每个查询/变更中单独处理。以下是具体实现步骤:

1. 编写日期格式化工具函数

先封装两个格式化函数,分别对应要求的日期格式:

// 格式化Date标量为 YYYY-DD-MM 格式(UTC时间)
const formatDate = (date) => {
  const d = new Date(date);
  const year = d.getUTCFullYear();
  const month = String(d.getUTCMonth() + 1).padStart(2, '0');
  const day = String(d.getUTCDate()).padStart(2, '0');
  return `${year}-${day}-${month}`;
};

// 格式化DateTime标量为 YYYY-DD-MMTHH:mm:ssZ 格式(UTC时间)
const formatDateTime = (date) => {
  const d = new Date(date);
  const year = d.getUTCFullYear();
  const month = String(d.getUTCMonth() + 1).padStart(2, '0');
  const day = String(d.getUTCDate()).padStart(2, '0');
  const hours = String(d.getUTCHours()).padStart(2, '0');
  const minutes = String(d.getUTCMinutes()).padStart(2, '0');
  const seconds = String(d.getUTCSeconds()).padStart(2, '0');
  return `${year}-${day}-${month}T${hours}:${minutes}:${seconds}Z`;
};

2. 解析GraphQL变量类型并处理变量

通过graphql库的visit方法解析请求中的变量类型,再递归遍历变量,对Date对象按对应标量类型格式化:

import { visit } from 'graphql';

// 解析请求文档,获取变量名与对应GraphQL类型的映射
const getVariableTypes = (document) => {
  const variableTypes = {};
  visit(document, {
    VariableDefinition(node) {
      // 处理非-null、列表等包装类型,提取原始标量名称
      const typeName = node.type.name?.value || node.type.type.name.value;
      variableTypes[node.variable.name.value] = typeName;
    },
  });
  return variableTypes;
};

// 递归处理变量,自动格式化Date对象
const processVariables = (variables, variableTypes) => {
  if (!variables) return variables;

  return Object.entries(variables).reduce((acc, [key, value]) => {
    let processedValue = value;

    // 处理Date对象:根据变量的GraphQL类型选择格式化方式
    if (value instanceof Date) {
      const type = variableTypes[key];
      if (type === 'Date') {
        processedValue = formatDate(value);
      } else if (type === 'DateTime') {
        processedValue = formatDateTime(value);
      }
    }
    // 递归处理嵌套对象
    else if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
      processedValue = processVariables(value, variableTypes);
    }
    // 处理数组中的Date对象或嵌套对象
    else if (Array.isArray(value)) {
      processedValue = value.map(item => {
        if (item instanceof Date) {
          const type = variableTypes[key];
          if (type?.includes('Date')) {
            return formatDate(item);
          } else if (type?.includes('DateTime')) {
            return formatDateTime(item);
          }
        } else if (typeof item === 'object' && item !== null) {
          return processVariables(item, variableTypes);
        }
        return item;
      });
    }

    acc[key] = processedValue;
    return acc;
  }, {});
};

3. 创建自定义Exchange并配置到urql Client

用mapExchange创建自定义拦截器,将其加入urql的exchange链中:

import { mapExchange } from '@urql/core';
import { createClient, dedupExchange, cacheExchange, fetchExchange } from '@urql/core';
import { Provider } from 'urql-react';

// 自定义日期处理Exchange
const dateScalarExchange = mapExchange({
  outgoing(operation) {
    const variableTypes = getVariableTypes(operation.document);
    const processedVariables = processVariables(operation.variables, variableTypes);
    return { ...operation, variables: processedVariables };
  },
});

// 创建urql Client并添加自定义Exchange
const client = createClient({
  url: '/your-graphql-endpoint', // 替换为你的GraphQL接口地址
  exchanges: [
    dedupExchange,
    cacheExchange,
    dateScalarExchange, // 需放在fetchExchange之前
    fetchExchange,
  ],
});

// 在应用根组件中使用Provider
function App() {
  return (
    <Provider value={client}>
      {/* 你的应用组件 */}
    </Provider>
  );
}

注意事项

  • 如果后端定义的标量名称不是Date/DateTime,需修改processVariables中的类型判断逻辑,替换为后端实际的标量名。
  • 示例中使用UTC时间格式化,若需本地时间,将getUTCFullYear等方法替换为getFullYear、getMonth等。
  • 对于复杂的嵌套数组或自定义标量场景,可根据业务需求调整processVariables的处理逻辑。

内容的提问来源于stack exchange,提问作者Muhammad Kashif Nazar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 12:35:19