Search code examples
reactjsstyled-components

"Should have unique key prop" when I have unique keys for all components inside


I'm getting following warning message, which is saying that I need a unique key prop.

front_1     | Warning: Each child in a list should have a unique "key" prop. See https://reactjs.org/link/warning-keys for more information.
front_1     |     at ShortcutArea (webpack-internal:///./components/encoding/ShortcutArea.tsx:38:5)
front_1     |     at div
front_1     |     at I (/app/node_modules/styled-components/dist/styled-components.cjs.js:1:19218)
front_1     |     at div
front_1     |     at I (/app/node_modules/styled-components/dist/styled-components.cjs.js:1:19218)
front_1     |     at EncodingIndexPage (webpack-internal:///./pages/techutils/encoding/index.tsx:83:72)
front_1     |     at div
front_1     |     at I (/app/node_modules/styled-components/dist/styled-components.cjs.js:1:19218)
front_1     |     at div
front_1     |     at I (/app/node_modules/styled-components/dist/styled-components.cjs.js:1:19218)
front_1     |     at Layout (webpack-internal:///./components/common/Layout.tsx:41:3)
front_1     |     at GlobalProvider (webpack-internal:///./libs/context/GlobalProvider.tsx:49:3)
front_1     |     at MyApp (webpack-internal:///./pages/_app.tsx:36:3)
front_1     |     at ae (/app/node_modules/styled-components/dist/styled-components.cjs.js:1:13294)
front_1     |     at AppContainer (/app/node_modules/next/dist/server/render.js:293:29)

However, I do happen to have a unique key for every component inside. I'm using Next.js + styled-component, and in those examples, ShortcutSelection is a styled div, if that could be a relevant bit in this case.

const ShortcutSelection = styled.div`
    color: rgba(0,0,0,0.5);
    :hover {
        background-color : rgba(0,0,0,0.05);
        cursor : pointer;
        color : rgba(0,0,0,0.8);
        font-weight : 600;
    }

code :

export default function ShortcutArea({handler, ...props}){

const ShortcutClickHandler = (e) => {
    handler.setEncoding(e);
}

return (<>
        {
            options.map((item, index) =>      
                <>
                    <h2 key = {index}>{item.title}</h2>       
                    {item.data.map((shortcut,idx) =>                         
                            <ShortcutSelection key = {index + "_" + idx}  
                                    onClick={ShortcutClickHandler}
                                    data-currentencoding={shortcut.from}
                                    data-targetencoding={shortcut.to}
                                    data-payload={shortcut.payload}     
                                    data-action={shortcut.action}                         
                            >{shortcut.displaytext}
                            </ShortcutSelection>
                    )}                    
                </>
            )   
        }
</>)
}

options is an array of javascript objects, and each of the item has data which is also an array that consists of javascript objects, thus the nested map feels required for me. options sample would looks like :

const options = [
    {    
        "title" : "List of fruits",
        "data" : [
                {
                    "displaytext" : "Apple",
                    "description" : "This Apple is quite delicious"
                    
                },
                {
                    "displaytext" : "Banana",
                    "description" : "Banana is also quite good"
                },
            ]   
    },
    {    
        "title" : "List of Veggies",
        "data" : [
                {
                    "displaytext" : "lettuce",
                    "description" : "It's a lettuce!"                    
                }
            ]   
    },
]

So the outcome is something like :

List of fruits (h2)
 Apple (styled with ShortcutSelection)
 Banana (styled)
List of Veggies (h2)
 lettuce (styled)

The output itself is working and is fully functional. However I'm confused on why I'm getting a unique key prop warning, despite me having key in every component inside. Is there anything I'm missing?

Please let me know if any additional information is required.


Solution

  • You should assign key to the parent element of the mapped element, in your case:

    return (<>
            {
                options.map((item, index) =>      
                    <div key={index}>
                        <h2 >{item.title}</h2>       
                        {item.data.map((shortcut,idx) =>                         
                                <ShortcutSelection key = {index + "_" + idx}  
                                        onClick={ShortcutClickHandler}
                                        data-currentencoding={shortcut.from}
                                        data-targetencoding={shortcut.to}
                                        data-payload={shortcut.payload}     
                                        data-action={shortcut.action}                         
                                >{shortcut.displaytext}
                                </ShortcutSelection>
                        )}                    
                    </div>
                )   
            }
    </>)
    }