5

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.

skyboyer
  • 22,209
  • 7
  • 57
  • 64
TayLorWebK
  • 57
  • 1
  • 1
  • 6

1 Answers1

11

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.

johnny peter
  • 4,634
  • 1
  • 26
  • 38