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

React 19中基于RSC与Server Action构建表单及解决输入重置问题

React 19 RSC + Server Action 表单提交错误后输入框清空的优化方案

问题背景

使用React 19的RSC(React Server Component)与Server Action构建高性能表单,表单主体以RSC实现,仅通过小型客户端组件封装提交逻辑。当前存在核心问题:当Server Action返回错误时,输入框内容会被清空,现有解决方案(如受控组件、将控件移入客户端组件)会破坏RSC特性或增加耦合性。

可行优化方案

方案1:Server Action返回输入值,客户端组件动态注入defaultValue

此方案无需修改RSC部分代码,仅调整Server Action和客户端表单组件,完整保留RSC特性与低耦合性。

步骤1:修改Server Action,返回错误时携带用户输入值

// actions.js
'use server'

export async function uploadDataset(prevState, formData) {
  const title = formData.get('title')
  const description = formData.get('description')

  // 示例验证逻辑
  if (!title?.trim()) {
    return {
      error: '标题不能为空',
      values: { title, description } // 携带用户提交的输入值
    }
  }

  // 业务逻辑:上传数据集等
  return { error: null, values: {} }
}

步骤2:修改客户端MyForm组件,遍历子元素注入defaultValue

'use client'

import { Fieldset, Form } from '@heroui/react'
import { useActionState, Children, cloneElement } from 'react'

type FormState = {
  error: string | null
  values?: Record<string, string | null>
}

export function MyForm({ action, children }) {
  const [state, submitAction, isPending] = useActionState(action, {
    error: null,
    values: {}
  })

  // 遍历表单子组件,给Input设置对应defaultValue
  const processedChildren = Children.map(children, (child) => {
    // 识别HeroUI的TextField组件(根据实际组件displayName调整)
    if (child.type?.displayName === 'TextField') {
      const fieldName = child.props.name
      const savedValue = state.values?.[fieldName]

      // 遍历TextField的子元素,找到Input并注入值
      return cloneElement(child, {}, Children.map(child.props.children, (inputChild) => {
        if (inputChild.type?.displayName === 'Input') {
          return cloneElement(inputChild, {
            defaultValue: savedValue ?? inputChild.props.defaultValue
          })
        }
        return inputChild
      }))
    }
    return child
  })

  return (
    <Form onSubmit={submitAction} validationErrors={state?.error}>
      <Fieldset disabled={isPending} className='h-full flex flex-col gap-0'>
        {processedChildren}
      </Fieldset>
    </Form>
  )
}

方案2:利用React 19原生keepDirtyValues属性

React 19原生<form>组件支持keepDirtyValues属性,提交失败时会自动保留用户输入。若HeroUI的<Form>组件透传该属性给原生表单,可直接启用:

// 在MyForm的Form组件中添加keepDirtyValues
<Form onSubmit={submitAction} validationErrors={state?.error} keepDirtyValues>
  {/* ...原有内容... */}
</Form>

此方案代码最简洁,但需确认HeroUI的Form组件是否支持将该属性传递到原生DOM元素。

方案优势

  • 完整保留RSC特性:表单主体仍为RSC,保证加载速度与JS体积优势
  • 低耦合:无需调整原有RSC结构,表单控件仍由RSC渲染
  • 体验优化:提交失败后自动填充用户之前的输入,无需重新输入

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.02 00:34:54