Yesterday I added react-router-dom
to my project and now when I leave and come back to my Sky
element in my nav, it reloads the sky and I get
Warning: flattenChildren(...): Encountered two children with the same key,
element-id-50
. Child keys must be unique; when two children share a key, only the first child will be used.
(the number 50 used above is just an example, it throws this error ~40 times each time all with different ids)
The problem seems to stem from here in my sky.js
file:
componentWillMount() {
this.props.dispatch(requestSkySetup());
this.props.dispatch(requestAllElements());
this.setState({loadedSky: true, loadedElements: true});
}
Since each time I'm going to another screen, this component is unmounting and then re-mounting when I come back.
When receiveSkySetup
is finished, the render
function in sky.js
creates a bunch of divs called Sector
s and each Sector
creates a few divs called Slot
s.
Then inside of Slot.render
I have:
return connectDropTarget(
<div className={showOutline ? 'slot showOutline' : 'slot'} style={style} onClick={interactable ? this.handleClick : null}>
{
elements
.map(e => (
<SkyElement
id={e.id}
key={`element-id-${e.id}`}
title={e.title}
size={150}
opacity={e.opacity}
glow={e.glow}
color={e.color}
sectorId={e.sectorId}
slotId={e.id}
dispatch={this.props.dispatch}
isDragging={false}
transformElement={false} />
))
}
</div>
);
The key
element in the SkyElement
call above is what's throwing the 40+ errors on each mounting.
Happy to provide more code if needed.
Any help would be hugely helpful. Thanks!
Edit: Console logging elements
Digging in a bit more, the items are doubling in my store.
So, on the 2nd render of the sky
tab, the full list of element ids is ["0", "1", "2", "3", "4", "5", "6", "7", "17", "18", "19", "55", "56", "57", "58", "59", "60", "61", "62", "63", "64", "65", "66", "67", "77", "78", "0", "1", "2", "3", "4", "5", "6", "7", "17", "18", "19", "55", "56", "57", "58", "59", "60", "61", "62", "63", "64", "65", "66", "67", "77", "78"]
On the 3rd render, elements 0-78 (the ids that apply from the array above) will be added again to the array
In Slot.js
const mapStateToProps = ({elements}, ownProps) => {
return {
elements: getElementsBySlotId(elements, ownProps.id),
};
};
elements
here will be n
times the number of loads that Sky
has done.
In sky.js
const mapStateToProps = ({sky, elements}) => {
return {
sectors: getSky(sky).sectors,
elements: getElementsByKeyName(elements, 'visibleElements'),
unplacedElements: getElementsByKeyName(elements, 'unplacedElements'),
};
};
Printing elements.length
I see that they double here too. Slot.js is pulling from the same store, so that makes sense
In my elements/reducer.js
case 'receiveAllElements':
const visibleElements = {};
const unplacedElements = {};
const elements = action.elements.reduce((result, index) => {
result[`${index.id}`] = index;
return result;
}, {});
const keys = Object.keys(elements);
for (const key of keys) {
const e = elements[key];
if (e.sectorId === null) {
unplacedElements[key] = e;
} else {
visibleElements[key] = e;
}
}
const visibleIds = Object.keys(visibleElements);
const unplacedIds = Object.keys(unplacedElements);
console.log(visibleIds);
console.log(unplacedIds); // logging these, the numbers are consistent and don't double, triple etc with each load
return {
...state,
elementsMap: {
...state.elementsMap,
...elements,
},
visibleElements: [...state.visibleElements, ...visibleIds],
unplacedElements: [...state.unplacedElements, ...unplacedIds],
};
Maybe something in there is causing the count to double?