What If you need to render a lot of input boxes in screen?. Efficiently Render Hundreds of Thousands of Input Boxes in React.
Here is a way to load hundreds of for elements in a single screen using react and lazy loading, redux etc.
Rendering a massive number of input boxes (100,000+) on a single screen can be challenging in React. It’s crucial to optimize performance to avoid sluggish user experiences. Here, we’ll explore techniques for tackling this task effectively.
lets assume, the data input is an array of array (matrix). createData
function is used to create some random data. like below
[
[1,2,3,4,5, ...],
[2,3.4,5,6, ...],
[3,5,6,7,4, ...]
....
]
import React from "react";
import { useState } from "react";
import "./worst.css"
const createData = (count) => {
const val: any[][] = [];
for (let i = 0; i < (count || 1000) ; i++) {
val.push(
Array.from({ length: count || 40 }, () => ({
value: Math.floor(Math.random() * 10),
}))
);
}
return val;
};
const App = (props) => {
const [data, setData] = useState(createData(400))
const update = (e, i, j) => {
const temp = [...data]
temp[i][j] = {value: e.target.value}
setData(temp)
}
return (
<div>
<table>
<tbody>{data.map((d, i) => {
return <tr>{d.map((p, j) => {
return <td><input value={p.value} onChange={(e)=>update(e, i, j)}/></td>;
})}</tr>
})}</tbody>
</table>
</div>
);
}
export default App;
Hmmm! It is able to load the screen but when you type something it is too slow!,
Why it is slow?
Because, on each input box change it is re-rendering the component, looping through all the array of array’s and re building the entire table again!.
The current approach suffers from excessive re-rendering. Every input change triggers a re-render of the entire App component, including all input elements. This is inefficient and leads to performance issues with large tables.
Lets try splitting it into smaller components — https://github.com/sojinantony01/react-spread-sheet/blob/solutions/src/child-componets/index.tsx like this, But, this is also getting re-rendered on each character type.
Okay, lets try adding context — https://github.com/sojinantony01/react-spread-sheet/blob/solutions/src/context/index.tsx, Still re-rendering all the table, child components and the input.
Lazy Loading — https://github.com/sojinantony01/react-spread-sheet/blob/solutions/src/lazyloading/index.tsx, Hmm this looks good, it is not slow anymore , But it is still looping through all the input boxes and re-rendering input boxes.
Okay lets try our another solution, and is there in way not to render subling input boxes in input change.
React-spread-sheet-excel using redux
Lets use Lazy loading with — react-intersection-observer helps render items in view port.
Redux and redux toolkit — Complete state management, and react redux useSelctor helps to manage re render only if required items are updated in state
const MyComp = () => {
const myVal = useSelector((state) => {
state.someReducer.someObject.myValue
})
return <div>{MyVal}</div>
}
//This COmponent will only re render is myValue inside `someReducer.someObject` is updated
// It will not re render is someReducer or The Object is updated.
Solution
Read row of matrix first and add a for loop till row, like here and here. For columns Lets pass each row index to column and read column length there like — here. Now for each input box read the value using rowIndex and column index like here
The solution is able to load 1lakh+ input boxes easly. And this solution is used in component —react-spread-sheet-excel
Update — Latest solution — No more Redux.
My previous solution was using Redux and its power full useSelector For controlling the unwanted re rendering. But By using redux the package size got increased 3 times!, Which i was not happy at all.
Found another solution — No more Redux (Or context) create Own global state and create own “useSelector” with the help of usesyncexternalstore. Check my new solution here. After removing the package size got reduced to 150KB from 622KB. Check version 2.1.6 and 3.0.0 in npm package.
Component supports large number of input boxes, the sibling components will not re render when you type one input box. Component supports math calculations, formatting styles, Keyboard events etc…
Thank you!
Sojin Antony
Top comments (0)