So I am working in React.js. I need to generate three versions of the same list, but with a different set of markets contained inside of each of the three events. I expect the events to be the same. But when they are linked to the markets, each of the three same events might have a different sub-set of markets based on the filer.
organiseEvents(timeFilter) { const propevents = this.props.Properties.events; const propmarkets = this.props.Properties.markets; const propselections = this.props.Properties.selections; let events = new Array(); propevents.forEach(e => { e.Markets = propmarkets.filter(m => m.Values.eventid === e.Id && m.Values.name.toUpperCase().includes(timeFilter)); e.Markets.forEach(m => { m.Selections = propselections.filter(s => s.Values.marketid === m.Id); }); events.push(e); }); if(events.length > 0) { events = events.sort(function (a, b) { return a.Values.homerotation - b.Values.homerotation }); return events; } else{ return []; } } render() { let events = this.organiseEvents(""); let midevents = this.organiseEvents("MIDEVENT"); let postevents = this.organiseEvents("POSTEVENT"); }
The issue I am having is:
- this.organiseEvents(“”) runs: events contains two ‘event’ objects with three markets each.
- this.organiseEvents(“MIDEVENT”) runs: midevents contains the same two ‘event’ objects, but with no markets as there was no market to match the filter.
- events also becomes the result of this.organiseEvents(“MIDEVENT”).
- events and midevents will then become the result of this.organiseEvents(“POSTEVENT”)
There is a reference issue somewhere and I can’t for the life of me spot it. I feel like I am missing the obvious.
Each three let variables should be three completely separate representations of the same two events, but with varying markets contained within.
One fix I have discovered in the mean time is the following:
let events = JSON.parse(JSON.stringify(this.organiseEvents(""))); let midevents = JSON.parse(JSON.stringify(this.organiseEvents("MIDEVENT"))); let postevents = JSON.parse(JSON.stringify(this.organiseEvents("POSTEVENT")));
This forces each of the three values to not reference the same place. However, it is a dirty fix in my eyes that conveniently fixes the problem rather than me understanding what the problem is and fixing it properly.
Thanks.
Advertisement
Answer
Every time organizeEvents
function is called, it’s just using the same array and mutating/changing it.
Where is same array used ?
const propevents = this.props.Properties.events; // (Properties.events) is an array that you are mutating
Here you just assigned the array to a variable propevents
. It does not mean that the array is copied to the variable. The variable is just referring the same array.
Where is the array mutated/changed ?
1.
propevents.forEach(e => { e.Markets = propmarkets.filter(m => m.Values.eventid === e.Id && m.Values.name.toUpperCase().includes(timeFilter));
Here you are looping through the propevents
array and for every element in that array your mutating/changing the property Markets
(which is an array).
2.
e.Markets.forEach(m => { m.Selections = propselections.filter(s => s.Values.marketid === m.Id); });
Here again your looping through the above mutated/changed Markets
and for every element in the Markets
array you are mutating/changing the propery Selections
(which is also an array).
Solution
Solution for this problem is to deep copy the array and mutate/change it.
How
You can make a utility function that deep copies array and object.
// it's not the best but it does the job function deepCopy(o) { let output, v, key; output = Array.isArray(o) ? [] : {}; for (key in o) { v = o[key]; output[key] = typeof v === "object" && v !== null ? deepCopy(v) : v; } return output; };
Use it in the
organizeEvents
functionconst propevents = deepCopy(this.props.Properties.events);