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

Reactjs:按渲染次数依次获取数组元素的实现难题

问题分析与解决方案

核心问题

当前代码里的renderCount是getInitialValue函数内部的局部变量,每次调用函数都会重新初始化0,所以永远无法递增,导致每次都返回数组第一个元素。另外,直接在非React组件/自定义Hook的函数里使用useRef/useState会违反React Hook规则,引发错误。

解决方案

我们需要把计数器改成跨函数调用持久化的状态,同时避免全局状态污染多个表单实例。这里用WeakMap绑定到表单的context对象,每个表单实例拥有独立的计数器:

// 用WeakMap存储每个表单上下文对应的渲染计数,避免跨实例干扰
const renderCounters = new WeakMap<EncounterContext, number>();

export const ProgramWorkflowHandler: SubmissionHandler = {
  handleFieldSubmission: (field: FormField, value: any, context: EncounterContext) => {
    return value;
  },
  getInitialValue: (
    encounter: OpenmrsEncounter,
    field: FormField,
    allFormFields: Array<FormField>,
    context: EncounterContext,
  ) => {
    // 初始化当前上下文的计数器
    if (!renderCounters.has(context)) {
      renderCounters.set(context, 0);
    }
    let renderCount = renderCounters.get(context)!;
    const programWorkflows = getPatientProgram(context.patientPrograms, context.programUuid);

    if (field.type === 'programWorkflow') {
      // 修正逻辑:取第一个患者项目下的对应索引状态(匹配你的数组结构)
      const targetState = programWorkflows[0]?.states[renderCount];
      const workflowUuid = targetState?.state?.programWorkflow?.uuid;
      
      // 仅在成功获取值时递增计数器,避免无效计数
      if (workflowUuid) {
        renderCounters.set(context, renderCount + 1);
      }
      return workflowUuid;
    }
    
    if (field.type === 'programState') {
      // 如果有多个programState字段,也可以复用计数器逻辑,这里保持原有逻辑
      const programStateUuid = programWorkflows[0]?.states?.find(state => !state.state.retired)?.state.uuid;
      return programStateUuid;
    }
    
    return undefined;
  },
};

关键说明

  1. 计数器持久化:WeakMap会将计数器绑定到表单的context对象,每次调用getInitialValue时,同一个表单的计数器会保持递增,不同表单互不干扰。
  2. 逻辑修正:原代码中programWorkflows[renderCount]不符合你的数组结构(示例里programWorkflows是单元素数组,每个元素包含states数组),所以改为取programWorkflows[0].states[renderCount]。
  3. 避免Hook错误:因为ProgramWorkflowHandler不是React组件,不能直接用Hook,用WeakMap是更合适的状态持久化方式,不会违反React规则。

额外注意事项

  • 如果表单重新加载(比如context对象更新),WeakMap会自动识别新的context并初始化新计数器,无需额外处理。
  • 若需要在表单卸载时清理计数器,可在表单组件的useEffect中添加renderCounters.delete(context)逻辑(如果能访问到context和renderCounters)。

内容的提问来源于stack exchange,提问作者CKW

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 23:05:19