1

ERROR:

main.js:1583 Uncaught Error: Objects are not valid as a React child (found: [object HTMLTableElement]). If you meant to render a collection of children, use an array instead or wrap the object using createFragment(object) from the React add-ons.


CODE:

var size = 40

var Board = createReactClass ({

    getInitialState() {
        var array = [];
        var cellsArray = [];
        for (var i = 0; i < size; i ++) {
            array.push(cellsArray);
            for (var j = 0; j > size; j++) {
                array[i].push(<Cell start={this.props.start}/>);
            }
        }

        return {
            array: array
        };

    },

    render() {

    var i = 0;

    var tableData = this.state.array.map(rowData => {
        i++
        return (
            <tr key={i}>
                {
                    rowData.map(cellData => {
                        return ({cellData});
                    })
                }
            </tr>
        );
    })

    return (
        <table>
            <tbody>
                {tableData}
            </tbody>
        </table>
    );

}

})

var Cell = createReactClass ({

    getInitialState() {
        return {
            selected : false,
        }
    },

    handleClick() {
        this.setState({
            selected: !this.state.selected
        })
    },

    render() {
        return <td onClick = {this.handleClick} className={this.state.selected ? "cell selected" : "cell"}></td>;
    }
})

QUESTION:

I would like to render the programmatically created table. How can I do that ?


UPDATE:

enter image description here

enter image description here


CSS:

.cell {
    width: 1em;
    height: 1em;
    border: 1px solid #ddd;
}

.selected {
    background-color: black;
}

table {
    border: 1px solid black;
    border-collapse: collapse;
    margin: auto;
    margin-bottom: 50px;
}
2
  • document.createElement('table') is a bad idea, just return <table>{tableData.map(rowData => <tr>... and so on Commented Apr 22, 2017 at 10:29
  • @elmeister Could you please put this in an answer so I can accept it ? Commented Apr 22, 2017 at 10:30

1 Answer 1

3

You need to create it React way. Your createTable method should look something like below.

createTable(tableData) {
 return (
  <table>
   <tbody>
   {
    tableData.map(rowData => {
      return (<tr key={rowData.Id}>
          {
           rowData.map(cellData => {
              return (<td key={cellData}> {cellData} </td>);
           })
          }
        </tr>);
    })
   }
  </tbody>
  </table>
 )

Note: You need to put in a unique key for the root of jsx inside the 'maps'. Identify the unique key for each iteration. As a last resort you can use index, but that is not recommended.

EDIT: Updated for new changes

In your updated code, the td is empty and hence its displayed empty on the page.

Other changes you would require

Your initial state should not generate an JSX. It should be used only to compute the initial state and return a plain object. You are returning a object that contains array of JSX elements in it, which fundamentally defeats the purpose of React that it needs to require the DOM to be dynamically updated appropriately based on prop/state changes. Your initialState should only contain the data that is required to construct the needed DOM elements.

getInitialState() {
    var array = [];
    var cellsArray = [];
    for (var i = 0; i < size; i ++) {
        array.push(cellsArray);
        for (var j = 0; j > size; j++) {
            array[i].push(/* push data that you need to construct your cell */);
        }
    }

    return {
        array: array
    };

}

Then in your tableData function , you need to form the required JSX. This function is getting called inside of render which is perfectly fine place to produce the DOM elements.

var tableData = this.state.array.map(rowData => {
    i++
    return (
        <tr key={i}>
            {
                rowData.map(cellData => {
                    return <Cell key={cellData} data={cellData} start={this.props.start} />
                })
            }
        </tr>
    );
})

Finally in your Cell, render method you need to pass some children for td for it to be visible on the screen. In you question its empty and so the image you have posted showing the DOM elements and it being empty is the right behaviour. You need to do something like below

render() {
    return (<td onClick = {this.handleClick} className={this.state.selected ? "cell selected" : "cell"}>
 {this.props.data }
 { /*  or whatever data you want to be put here */ }
  </td>);
 }
Sign up to request clarification or add additional context in comments.

4 Comments

Warning: Each child in an array or iterator should have a unique "key" prop. Check the top-level render call using <tbody>.
well. That is pretty much updated now. Always you need to make modifications to the code to suit your needs.
Its bad idea to create the JSX components in other places that inside render's context. You have to move it inside the <td> by putting the logic inside it. State should only hold plain javascript objects.
1) Change var j = 0; j > size; j++ to var j = 0; j < size; j++, 2) Change return ({cellData}); to return (cellData);

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.