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?
The React error "Encountered two children with the same key" occurs when two or more of the elements we return from the map() method have the same key prop. To solve the error, provide a unique value for the key prop on each element or use the index parameter.
The easiest fix for this is to create a separate component for the items you're mapping and add the key to that component. Create a new component above your existing component (or link to it your call).
A “key” is a special string attribute you need to include when creating lists of elements in React. Keys are used to React to identify which items in the list are changed, updated, or deleted. In other words, we can say that keys are used to give an identity to the elements in the lists.
The issue here was
return {
...state,
elementsMap: {
...state.elementsMap,
...elements,
},
visibleElements: [...state.visibleElements, ...visibleIds],
unplacedElements: [...state.unplacedElements, ...unplacedIds],
};
namely, the visibleElements
(and unplacedElements
values).
[...state.visibleElements, ...visibleIds]
will concat 2 arrays so since this code was being hit each time I went back to the Sky
tab, it was adding the new ids in ...visibleIds
, to the array I already had in ...state.visibleElements
and doubling values
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With