Justin Blayney
Justin Blayney

Reputation: 781

unique "key" prop. warning yet I have a key

I am getting an error in my console,

my JSON is here https://dev.justinblayney.com/wp-content/uploads/2020/12/main-menu.json_.zip

Warning: Each child in a list should have a unique "key" prop.

What displays on my page is (So they are all unique, so WTF react)

KEY: 2429 KEY: 2430 KEY: 3859 KEY: 2421 KEY: 2802 KEY: 2428

On a side note, I'm discovering that using a function is a terrible way to get a JSON file, I also get memory leak warnings and every tutorial I see online uses classes or axios

Check the render method of MyRoutes. See https://reactjs.org/link/warning-keys for more information. MyRoutes@http://localhost:3000/react-wordpress-headless/static/js/main.chunk.js:63:81 div Router@http://localhost:3000/react-wordpress-headless/static/js/0.chunk.js:35747:30 BrowserRouter@http://localhost:3000/react-wordpress-headless/static/js/0.chunk.js:35367:35 App@http://localhost:3000/react-wordpress-headless/static/js/main.chunk.js:94:1

    function MyRoutes() {
    
    const [myrt, setMyrt] = useState([]); 
  
    
    useEffect(() => {
        fetch("main-menu.json" ,{
      headers : { 
        'Content-Type': 'application/json',
        'Accept': 'application/json'
       }
    })
        .then(res => res.json())
    
        .then(json =>{
             setMyrt(json.items)}
              )
         });
        
    
    return (
        <>
            {Object.keys(myrt).map((ky, idx)=> (
            <>
             <h2>KEY: {myrt[ky].ID} </h2>
        <Route exact path={`/${myrt[ky].slug}`} component={Page} key={myrt[ky].ID}  /></>
            ))} 
        </>
  
    );
}

Upvotes: 0

Views: 734

Answers (4)

felixmosh
felixmosh

Reputation: 35603

The key prop should be defined on the first most element, in your case it is React.Fragment.

function MyRoutes() {
  const [myrt, setMyrt] = useState([]);

  useEffect(() => {
    fetch('main-menu.json', {
      headers: {
        'Content-Type': 'application/json',
        Accept: 'application/json',
      },
    })
      .then((res) => res.json())

      .then((json) => {
        setMyrt(json.items);
      });
  });

  return (
    <>
      {Object.keys(myrt).map((ky, idx) => (
        <React.Fragment key={ky}>
          // ------------^
          <h2>KEY: {myrt[ky].ID} </h2>
          <Route exact path={`/${myrt[ky].slug}`} component={Page} key={myrt[ky].ID} />
        </React.Fragment>
      ))}
    </>
  );
}

Upvotes: 3

topched
topched

Reputation: 775

For your memory leak you are calling the function get the JSON file infinite times because you have not specified any dependencies in the useEffect. So you set the data, it rerenders, then fetches again forever

    useEffect(() => {
        fetch("main-menu.json" ,{
      headers : { 
        'Content-Type': 'application/json',
        'Accept': 'application/json'
       }
    })
        .then(res => res.json())
    
        .then(json =>{
             setMyrt(json.items)}
              )
         }, [] /* Adding this only runs this once */);

Upvotes: 1

Brian Rigoni
Brian Rigoni

Reputation: 11

You need the key on the top component/tag that it's rendering on the map. Example: if you use a div

<div key={myrt[ky].ID} >
    <h2>KEY: {myrt[ky].ID} </h2>
    <Route exact path={`/${myrt[ky].slug}`} component={Page} />
</div>

Upvotes: 1

andi1984
andi1984

Reputation: 676

The key property is needed on the first-level of the list child element, thus I think in your example the React fragment within your .map needs to have this key.

Upvotes: 1

Related Questions