I have a list of cards that take the state tree. I have one selector that gets the list of jobs, then two selectors that use that selection to map and combine an object to pass into the card.
function ProductionJobs(props) {
const jobData = useSelector(getDataForProductionJobs);
const dataData = useSelector(getDataForProduction(jobData.map(x=>x.jobsessionkey)));
const matData = useSelector(getMatsForProduction(jobData.map(x=>x.jobsessionkey)));
console.count("renders");
const combined = jobData.map(x=> {
const foundData = dataData.find(y=>y.attachedJobKey===x.jobsessionkey);
const foundMaterial = matData.filter(z=>z.attachedJobkey===x.jobsessionkey);
const obj = {...x}
if(foundData) obj.foundData = foundData;
if(foundMaterial) obj.material = foundMaterial;
return obj;
});
const productionCards = combined.map(x=><ProductionJobCard key={x.jobsessionkey} props={x} />)
return <div className="ProductionJobs">{productionCards}</div>
}
The problem is - this re-renders unnecessarily. Is there a better way of combining this data on the reducer's side, instead of the component?
You can create a container for ProductionJobCard and select combined items in that one using shallowEqual as second argument when filtering matData items.
You should not combine the data on the reducer because you will essentially copy the data (combined data is essentially a copy of the data you already have). The combined data is a derived value and such values should not be stored in state but calculated in selectors, re calculate when needed by using memoization (not done here) but if you're interested you can see here how I use reselect for memoizing calculations.
At the moment the filter and find are run on each item but since the outcome is the same the component is not re rendered.