Reputation: 1098
I want to render a list of components that have a 1:1 relationship with some objects in my redux store.
My current code is:
props.images.forEach(imageFile => {
let objectURL = URL.createObjectURL(imageFile);
const newStyles = {
left: `${leftPosition}%`,
top: `${topPosition}%`
}
previewFloats.push(
<div className="Preview" style={{...style, ...newStyles}} key={v4()}></div>
)
});
return(
previewFloats
)
Edit: Example here (codesandbox.io/s/brave-mcnulty-0rrjz)
The problem being that performance takes a pretty big hit rendering an entire list of background images as the list grows.
What is a better way to achieve this?
Edit: still unsure why background-image src is triggering a re-render, but the suggestion to use an <img>
element instead has things working as intended.
Upvotes: 5
Views: 2526
Reputation: 1098
So thanks to Dergash on Github I've discovered that the problem is not that my list is re-rendered.
Because I am creating a new URL every time with URL.createObjectURL inside of my component and because 'backgroundImage' does not do image prefetching whereas src attribute does I am seeing the flicker.
So my mistake was not creating the URL first and then passing it down into the component.
Working example: https://codesandbox.io/s/funny-http-8vrgv
More details: https://github.com/facebook/react/issues/16187
Upvotes: 0
Reputation: 3982
Your answer is with 'key' property of react components. It's built for such cases Assuming this is render part of your component, you should have something like this:
return this.props.images.map(imageFile => (
<div className="Preview" key={imageFile}></div>
))
Assuming imageFile is a unique string. This way react will rerender your virtual dom but it'll recognise that there is no need to dom update for same elements with same key property
Upvotes: 2
Reputation: 5148
Array.map()
allows dynamic rendering of elements in React, so that only those who change their props will re-render (as explained in the documentation).
If you'll use this method - rather than create the full array and render it fully - React will only re-render elements that are supposed to be updated:
props.images.map((imageFile, index) => {
let objectURL = URL.createObjectURL(imageFile);
const newStyles = {
left: `${leftPosition}%`,
top: `${topPosition}%`
}
return (
<div className="Preview" style={{...style, ...newStyles}} key={index}></div>
)
});
Note that I've modified the key
property of each element in the array. It should be unique and I didn't know what v4()
is, so I just used the array indices.
React's documentation actually explains really well about these:
Keys help React identify which items have changed, are added, or are removed
Upvotes: 2