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

集成@dnd-kit与react-hook-form useFieldArray时遇即时过渡异常

问题:集成@dnd-kit与react-hook-form useFieldArray组件时的拖拽过渡异常

在集成@dnd-kit与react-hook-form的useFieldArray组件时,遇到异常问题:拖拽元素释放后会出现意外的即时过渡效果。为避免字段被立即更新,我创建了单独的副本用于UI层面处理,但问题仍未解决;即便未对字段或react-hook-form的状态进行任何更新,过渡依然是即时触发的。

相关代码如下:

type FormData = z.infer<typeof formDataSchema>

type UseSortableReturn = Omit<
  ReturnType<typeof useSortable>,
  'setNodeRef' | 'transform' | 'transition'
>

function SortableItem(props: {
  id: string
  children: (args: UseSortableReturn) => React.ReactNode
}) {
  const { setNodeRef, transform, transition, ...rest } = useSortable({
    id: props.id
  })

  const style = {
    transform: CSS.Transform.toString(transform),
    transition
  }

  return (
    <div ref={setNodeRef} style={style}>
      {props.children({ ...rest })}
    </div>
  )
}

export default function App() {
  const { control, setValue } = useForm<FormData>({
    resolver: zodResolver(formDataSchema),
    defaultValues: {
      people: new Array(6).fill(1).map((_, index) => ({
        fname: (index + 1).toString(),
        lname: (index + 1).toString()
      }))
    }
  })

  const modifiers = [restrictToVerticalAxis, restrictToParentElement]

  const { fields } = useFieldArray({ control, name: 'people' })

  const [items, setItems] = useState([...fields])

  useEffect(() => {
    fields.forEach((item, index) => {
      setValue(`people.${index}.fname`, items[index].fname)
      setValue(`people.${index}.lname`, items[index].lname)
    })
  }, [items, fields, setValue])

  return (
    <form className="w-full h-screen flex items-center justify-center px-8 max-w-screen-md mx-auto w-full">
      <div className="grid bg-green-400 p-2 gap-2 rounded">
        <DndContext
          modifiers={modifiers}
          onDragEnd={(event) => {
            const { active, over } = event
            if (over && active.id !== over?.id) {
              const oldIndex = items.findIndex((item) => item.id === active.id)
              const newIndex = items.findIndex((item) => item.id === over.id)
              const nextItems = arrayMove(items, oldIndex, newIndex)
              setItems(nextItems)
              console.log(nextItems.map((i) => i.fname))
            }
          }}
        >
          <SortableContext items={items}>
            {items.map((field) => {
              return (
                <React.Fragment key={field.id}>
                  <SortableItem id={field.id}>
                    {({ attributes, listeners }) => (
                      <div className="bg-green-200 rounded py-2 px-4 flex items-center space-x-4 select-none">
                        <div
                          className="w-8 h-8 rounded bg-blue-300 -ml-2"
                          {...attributes}
                          {...listeners}
                        />
                        <div className="font-mono font-semibold text-green-950 flex space-x-4 py-5">
                          <span>{field.fname}</span>
                          <span>{field.id.toUpperCase()}</span>
                        </div>
                      </div>
                    )}
                  </SortableItem>
                </React.Fragment>
              )
            })}
          </SortableContext>
        </DndContext>
      </div>
    </form>
  )
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 00:04:58