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.
A Parent Component
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
State updates in React are asynchronous; when an update is requested, there is no guarantee that the updates will be made immediately. The updater functions enqueue changes to the component state, but React may delay the changes, updating several components in a single pass.
When a value in the state object changes, the component will re-render, meaning that the output will change according to the new value(s).
React may batch multiple setState calls into a single update for performance. Because props and state may be updated asynchronously, you should not rely on their values for calculating the next state.
Use the useEffect hook to listen for state changes in React. You can add the state variables you want to track to the hook's dependencies array and the logic in your useEffect hook will run every time the state variables change. Copied! The second parameter we passed to the useEffect hook is an array of dependencies.
You have learned about different ways on how to manage React state with arrays. You can add items to an array, update an item in the array or update the whole array, and remove items from an array. Everything is possible with only JavaScript without using React for it. React is only used to set the state in the end.
The pain of updating a nested state stems from the fundamental architectural decision of the React to embrace immutability. Immutability comes with plenty of great benefits, such as predictability and performance, so the trade-off is worth it. There are two main ways to deal with the problem of updating a deeply nested state.
No matter the kind of technology you use, your app relies on some sort of state, be it in-memory, on a physical disc, and so on. In React, every component can handle its own state, which might mean clicking a button or the content of a text input.
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.
Copying large arrays shouldn't be the culprit, it only copies object references which is usually very fast, not an actual deep copy. In fact, Redux itself does it this way.
The reason you're experiencing this lag is you didn't set keys to the children. You should set unique keys and don't use the index as the key.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With