如何在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
相关产品推荐
相关产品推荐

