Akshay Kishore
Akshay Kishore

Reputation: 25

Rendering an array of objects in react

Im new to react so im not sure whats going wrong here... Im trying to create a 3x3 structure of input boxes. This is what i came up with

function Square(prop){
    return (<input type = 'text' class='w-25'  style="display:inline-block">${prop.key}</input>);
}

function Row(props){
    const row =[];
    for( let i=props.key*3;i<(props.key+3);i++){
        row.push(<Square key ={i}/>);
    }
    return (row);
}

class Box extends React.Component{
    constructor(props){
        super(props);
        this.state = {
            squares: Array(9).fill(null),
            xIsNext: true,
        };
    }
    render(){
        let board =[];
        for( let i=0; i<3;i++){
            board.push(<div><Row key={i} /></div>);
        } 
        return (board);
    }
} 
ReactDOM.render(
    <Box />,
    document.getElementById('root')
  );

But I am getting the error

Warning: Each child in an array or iterator should have a unique "key" prop.

As far as my Dom goes the 3 rows have been rendered as

Any help would be greatly appreciated

UPDATE

After trying out some answers given below I've ended up with a single row of 4 input boxes... although I've only specified 3 in the loop. Why is this can some one explain and I've specified 2 more rows.This is the new code

function Square(prop){
    return (<input type = 'text' id={prop.value} value={'x'}></input>);
}

function Row(props){
    const row =[];
    for( let i=props.value*3;i<(props.value+3);i++){
        const val = `${i}input`;
        const key = `${i}square`;
        row.push(<Square key ={key} value={val}/>);

    }
    return (row);
}

class Box extends React.Component{
    constructor(props){
        super(props);
        this.state = {
            squares: Array(9).fill(null),
            xIsNext: true,
        };
    }
    render(){
        let board =[];
        for( let i=0; i<3;i++){
            const key = `${i}row`;
            board.push( <Row  key={key} value={i}/>);
            console.log(i)
        } 
        return (board);
    }
} 
ReactDOM.render(
    <Box />,
    document.getElementById('root')
  );

Upvotes: 0

Views: 101

Answers (3)

omri_saadon
omri_saadon

Reputation: 10621

The key prop should be on the first element of the iteration which is the div element:

board.push(<div key={i}><Row /></div>);

Also note that this row for( let i=props.key*3;i<(props.key+3);i++) might not work for you as there is not more key prop.

You can change it to: for( let i=0;i<3;i++)

Notice that it is an Anti-Pattern to use index as a key.

a key is the only thing React uses to identify DOM elements. What happens if you push an item to the list or remove something in the middle? If the key is same as before React assumes that the DOM element represents the same component as before. But that is no longer true.

Took from This medium - Index as a key is an anti-pattern

EDIT:

Added a sample code that should run for you.

Notice I've removed the Row component as it seem redundant.

I didn't understood why you need two for loops? Do you need 9 inputs or 3 inputs?

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';

function Square(props) {
  return (<input type='text' id={props.key} value={props.value}></input>);
}

class Box extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      squares: Array(9).fill(null),
      xIsNext: true,
    };
  }
  render() {
    let board = [];
    for (let i = 0; i < 3; i++) {
      const key = `${i}row`;
      board.push(<Square key={key} value={i} />);
      console.log(i)
    }
    return (board);
  }
}
ReactDOM.render(
  <Box />,
  document.getElementById('root')
);

Upvotes: 0

Bhojendra Rauniyar
Bhojendra Rauniyar

Reputation: 85545

You should use key in parent element ie. div in your example:

for( let i=0; i<3;i++){
  board.push(<div key={i}><Row /></div>);
}

BTW, you may simply use:

for( let i=0; i<3;i++){
  board.push(<Row key={i} />);
}

Best practice is to use some string rather than assigning number value so it will not conflict with other key of element:

for( let i=0; i<3;i++){
  board.push(<Row key={'row-'+i} />);
}

Upvotes: 0

iofjuupasli
iofjuupasli

Reputation: 3873

Here you need to move key property:

board.push(<div key={i}><Row /></div>);

Because key should be in the outside element of each element in array

Upvotes: 2

Related Questions