setState 组件中的 setState 呈现整个组件

setState inside a setState component renders the whole component

我有一个 ant design modal,我使用 setState 调用它,它调用一个单独的组件,其中包含一个 ant design 表单,在模态主体内呈现,这就是功能组件的样子。

export default function EditTableCell({ record}) {
const [colorSwatch, setColorSwatch] = React.useState(record.color)
const [colorPalletVisible, setColorPalletVisible] = React.useState(false)


if (record === 'add') {
    form.setFieldsValue({
      description: '',
      notes: '',
    })
  }
    
    return (
         <Form>
          <Form.Item
           label="description"
           name="description"
          >
           <Input />
          </Form.Item>
        </Form>


        <Form.Item name="color" noStyle>
          <Avatar
            size={32}
            icon={<FormatPainterFilled />}
            style={{ backgroundColor: colorSwatch }}
            onClick={() => setColorPalletVisible(!colorPalletVisible)}
          />
        </Form.Item>
    )

现在的问题是每当我调用 setColorPalletVisible 时,组件都会重新呈现并且我输入的初始表单值会重新出现,这意味着当用户输入表单字段值,然后进行颜色选择时,它会重新呈现他们会丢失正在输入的数据。那么如何使它成为预期的 运行 组件呢?

https://ant.design/components/form/

您的组件主体不应调用任何可能改变状态和调用重新渲染函数的内容。

每次你调用 setState 方法,在这种情况下 setColorPalletVisible React 会重新渲染你的组件。但是,这里有 if 语句,每次调用组件 re-renders 又名 setColorPalletVisible 时都会执行该语句。

record变量的值改变时,你需要调用form.setFieldsValue,因此其他突变不应该调用这个函数。这叫做side effect.

在这里您可以阅读 Rect 提供的钩子来处理这种情况。

https://reactjs.org/docs/hooks-effect.html

简而言之,为了实现基于某些依赖项的副作用,您应该调用 useEffect 挂钩,它将在依赖项数组发生变化后执行代码。

在下面的代码中,仅当 record 值已更改且等于 add 时,才会调用 form.setFieldsValueuseEffect 依赖数组可以为空,只有在组件初始渲染后才会调用回调函数。

export default function EditTableCell({ record}) {
  const [colorSwatch, setColorSwatch] = React.useState(record.color)
  const [colorPalletVisible, setColorPalletVisible] = React.useState(false)

  useEffect(() => {
    if (record === 'add') {
      form.setFieldsValue({
        description: '',
        notes: '',
      })
    }
  }, [record])

  return (
     <Form>
        <Form.Item
         label="description"
         name="description"
        >
         <Input placeholder={t.payitemsGroupPage.enterPayitem} />
        </Form.Item>
      </Form>


      <Form.Item name="color" noStyle>
        <Avatar
          size={32}
          icon={<FormatPainterFilled />}
          style={{ backgroundColor: colorSwatch }}
          onClick={() => setColorPalletVisible(!colorPalletVisible)}
        />
      </Form.Item>
  )
}