Search code examples
javascriptreactjsfrontendstateonchange

Huge React State Array with Hundreds of Inputs, slow state changes onChange


I'm trying to a large React form, but each input in the form is complex and has a complex state. I keep the state of all of the inputs in a parent component, and each input is wrapped in a child component. I have a state array in parent that contains the current value of the state for all of the input elements. Currently, every time there's an onChange in the input, I try to reset the entire state array in the parent via setState(). This was okay with up to 5 inputs, but once I got above that (like a hundred inputs), I started to notice some serious lag in the program. Please note: the program will also allow you to rearrange, delete, and add inputs, so the state needs to accommodate those changes Ie. the first input could swap positions with the 2nd input or be inserted right after the 10th input.

My objective is to find a way to optimize the performance of this onChange. Ultimately, I don't really need the data to be in the parent component, I just need to collect the values for the inputs when I click save at the bottom of the page.

Just to reiterate, I have two components.

  1. A Parent Component

  2. A Child Component

The Child component is basically an input where users can write hundreds of lines of text.

The Parent component contains 100s of the children and essentially looks like this:

export default function Parent(props) {
  const [state, setState] = useState(createDummyData());
  useEffect(() => {});



  const onInputChange = (value, index) => {
    var tempValue = [...state];
    tempValue[index] = value;
    setState(tempValue);
  };

  return (
    <>
      <div style={{ display: "flex", flexDirection: "column" }}>
        {state.map((item, index) => (
          <Child
            value={state[index].content}
            index={index}
            onChange={onInputChange}
          />
        ))}
        <button style={{backgroundColor: "red"}}>save input data</button>
      </div>
    </>
  );
}

The child component looks like this

export default function Child(props) {
  useEffect(() => {});

  const onChange = event => {
    props.onChange(event.target.value, props.index);
  };

  return (
    <>
      <input value={props.value} onChange={onChange} />
    </>
  );
}

I haven't found a simple way around this. Some seem to suggest using Redux, others seem to say use a combination of useMemo and useEffect to prevent rerenders. Your help would be much appreciated.

One thing I noticed is that if I try to keep individual state within the Child components, they render onChange much faster. This is probably because it doesn't have to setState for the parent state array each time. If possible, I'd like to be able to simply go through and grab the state of the child nodes when I click save. Would I use a ref in this case? Is it possible to do it without a ref?

I'd also like to AVOID using onBlur() just for the purpose of this project

The codesandbox is copied down below for reference: https://codesandbox.io/s/cocky-knuth-jm8n6?fontsize=14


Solution

  • Created example with similar functional components and dummy data:

    https://codesandbox.io/s/recursing-cdn-q4vx0

    Have to create Child component with local item state and sync with main array. Added Delete and Add.

    Work with object arrays as your sample.