Reputation: 11
I am using React 17.0.2 and I have a performance issue related to how I render an array containing a large number of JSX elements (it may vary from 100 to ~650 elements).
In particular, I would like to show, in a scrollable container, a certain number of different "Cards" where each one of them contains a chart, images, icons and paragraphs. These details change everytime the SSE sends new data.
The code below works just fine and does what I was expecting it to do but the rendering is quite slow. The app I am working on should be used on mobiles too and I am afraid that the waiting would be a tad too much for a user to bear.
Contestants:
const Contestants = memo(() => {
return (
<div className={`${'contestants-container animate__animated animate__fadeIn'} ${classes.mainContainer}`}>
<div className={`${'mx-0 my-0'} ${classes.cardsContainer}`}>
<PerfectScrollbar>
<div className='d-flex flex-wrap align-items-center justify-content-evenly' >
<DetailCards />
</div>
</PerfectScrollbar>
</div>
</div>
)
})
export default Contestants
DetailCards
const DetailCards = memo(() => {
// ** Context
const fetchDataContext = useContext(FetchDataContext)
const vehicleData = fetchDataContext.vehicleData
const locationData = fetchDataContext.locationData
const payloadSSE = fetchDataContext.payloadSSE
// ** State
const [detailCardsArray, setDetailCardsArray] = useState([])
const [initialLocationFlag, setInitialLocationFlag] = useState(true)
const [initialLocationData, setInitialLocationData] = useState({})
const detailCardsArrayRef = useRef(detailCardsArray)
useEffect(() => {
if (detailCardsArray) {
detailCardsArrayRef.current = detailCardsArray
}
}, [detailCardsArray])
useEffect(() => {
setInitialLocationFlag(true)
}, [])
useEffect(() => {
if (initialLocationFlag === true && Object.keys(locationData).length !== 0) {
setInitialLocationData(locationData)
setInitialLocationFlag(false)
}
}, [locationData, initialLocationFlag])
useEffect(() => {
if (Object.keys(vehicleData).length !== 0 && Object.keys(initialLocationData).length !== 0) {
let temporaryDetailCardsArray = []
for (let i = 0; i < Object.keys(vehicleData).length; i++) {
temporaryDetailCardsArray.push(
<DetailCard
key={vehicleData[Object.keys(vehicleData)[i]].imei}
object1={vehicleData[Object.keys(vehicleData)[i]]}
object2={initialLocationData[Object.keys(vehicleData)[i]]}
/>
)
}
setDetailCardsArray(temporaryDetailCardsArray)
}
}, [vehicleData, initialLocationData])
useEffect(() => {
if (detailCardsArrayRef.current.length !== 0) {
if (typeof payloadSSE !== 'undefined' && payloadSSE !== null) {
for (let i = 0; i < detailCardsArrayRef.current.length; i++) {
if (detailCardsArrayRef.current[i].key === payloadSSE.imei) {
detailCardsArrayRef.current[i] = (
<DetailCard
key={detailCardsArrayRef.current[i].key}
object1={detailCardsArrayRef.current[i].props.object1}
object2={payloadSSE}
/>
)
}
}
}
setDetailCardsArray(detailCardsArrayRef.current)
}
}, [payloadSSE])
return detailCardsArray
})
export default DetailCards
So, is there a way to render the array faster? I thought about virtualization but I am unsure about how to implement it.
Thank you!
Upvotes: 0
Views: 68
Reputation: 11
The problem was solved by using @Piotr Żak suggestion to fetch a certain number of elements and give the user the option to load more. Furthermore, I added pagination as well. Now it works just fine even on mobiles.
Upvotes: 1