如果我在一个表单中有很多文本输入(挂钩),我该如何提高反应性能?

How can I improve the react performance if I have many text inputs (Hooks) in a form?

问题

我有一个表单可以通过 React 中的 api rest 发送数据,当我有大约 80 个文本字段时,渲染和在表单上书写的速度非常慢。

我正在使用带钩子的功能组件来处理输入文本,并使用 Material-UI 作为 UI 框架。 在第一次尝试中,我有一个柯里化函数来处理这些值:

setValue = (setter) => (e) => { setter(e.target.value) }

但是渲染过程真的很慢(因为我在每次渲染中都创建了一个函数),所以我将 setter 函数作为 prop 发送,然后它改进了一点但还不够。

实际上我在任何输入中写一个键时的输入响应大约是500毫秒。

我怎样做才能获得更好的性能?

为了便于理解,对代码进行了简化。

示例代码如下:

const [input1, setInput1] = useState('')
const [input2, setInput2] = useState('')
const [input3, setInput3] = useState('')
.
.
.
const [input80, setInput80] = useState('')

// render the Inputs
<Input value={input1} setter={setInput1} text="Some label text" />
<Input value={input2} setter={setInput2} text="Some label text" />
<Input value={input3} setter={setInput3} text="Some label text" />
.
.
.
<Input value={input80} setter={setInput80} text="Some label text" />

我的输入组件:

const Input = ({
  value, setter, text, type = 'text'
}) => {
  const handleChange = (e) => {
    const { value: inputValue } = e.target
    setter(inputValue)
  }
  return (
    <Grid>
      <TextField
        fullWidth
        type={type}
        label={text}
        value={value}
        onChange={handleChange}
        multiline={multiline}
      />
    </Grid>
  )
}

所有输入值都必须在一个组件中,因为我需要将它们发送到带有 axios 的服务器。

看起来 Material-UI 输入组件有点重。

我有一个 sample codesandbox here,我在其中初始化了大约 1000 个输入。最初它滞后并崩溃。

首先,我向 Input 组件添加了一个 memo。这会记住所有 Input 组件,只有当其中一个道具发生变化时才会触发新的渲染。

首先,只需将 memo 添加到您的输入组件。

import React, { memo } from 'react';

const Input = memo(({
  value, setter, text, type = 'text'
}) => {
  const handleChange = (e) => {
    const { value: inputValue } = e.target
    setter(inputValue)
  }
  return (
    <Grid>
      <TextField
        fullWidth
        type={type}
        label={text}
        value={value}
        onChange={handleChange}
        multiline={multiline}
      />
    </Grid>
  )
})

注意: 如果您有一个自定义的 setter,就像您的第一个案例 setValue = (setter) => (e) => { setter(e.target.value) },您可以将其包装在 useCallback 中以防止为每个渲染器创建多个函数。