简体   繁体   中英

Warning: flattenChildren(…): Encountered two children with the same key / Child keys must be unique

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 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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM