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

12,237

It looks like the Material-UI Input component is a bit heavy.

I have a sample codesandbox here where I initialised around 1000 inputs. Initially it lagged and crashed.

To begin with I added a memo to the Input component. This memoizes all the Input components, triggering a new render only if one of its props has changed.

For a start just add a memo to your input component.

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>
  )
})

Note: If you have a custom setter like in your first case setValue = (setter) => (e) => { setter(e.target.value) }, you can wrap that in a useCallback to prevent multiple functions to be created for every render.

Share:
12,237
Admin
Author by

Admin

Updated on June 04, 2022

Comments

  • Admin
    Admin almost 2 years

    The Problem

    I have a form to send data through a api rest in React, the render and the writing on the form is very slow when I have about 80 text fields.

    I'm using functional components with hooks to handle the input texts and Material-UI as UI framework. In a first try, I had a currying function to handle the values:

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

    But the render process was really slow (because I was creating a function in every render), So I send the setter function as a prop, then it improves a little but not enough.

    Actually the input response when I write a key in any input, it's about 500 ms.

    What can I do to get a better performance?

    The code was simplified for understanding purposes.

    Sample code below:

    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" />
    
    

    My Input components:

    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>
      )
    }
    

    All input values are must be in a component because I'm need to send them to a server with axios.