Placebo Placebo - 3 months ago 12
Javascript Question

ReactJS - Cannot read property 'updateNumber' of undefined"

New to js and React, trying to make a basic Sudoku program.

When I add UpdateNumberInCell={this.updateNumber} as a property in the Cell component, I get the error: "Uncaught TypeError: Cannot read property 'updateNumber' of undefined". I've stared at this for an hour and don't understand what's wrong. Probably something very basic.

Complete code:

class Cell extends React.Component {

constructor(props) {
super(props);

this.state = {editing: false};
}

editCell() {
this.setState({editing: true});
}

editingDone() {
let number = this.refs.newNumber.value;
this.props.updateNumberInCell(number, this.props.index);
this.setState({editing: false});
}

renderEditing() {
return <td><textarea ref="newNumber" onBlur={this.editingDone.bind(this)} onKeyPress={this.editingDone.bind(this)} defaultValue={this.props.children}
maxLength="1" cols="1" rows="1" autoFocus /></td>;
}

renderNormal() {
if (this.props.editable) {
return <td onClick={this.editCell.bind(this)}>{this.props.children}</td>;
} else {
return <td>{this.props.children}</td>;
}
}

render() {
if (this.state.editing) {
return this.renderEditing();
} else {
return this.renderNormal();
}
}

}


class Board extends React.Component {

constructor(props) {
super(props);

let boardList = [];
let i = 0;
for (let r = 0; r < 3; r++) {
boardList.push([]);
for (let c = 0; c < 3; c++) {
let number = this.props.boardString[i];
if (number !== "0") {
boardList[r].push(
{
"index": i,
"number": number,
"editable": false,
"inConflict": false
});
} else {
boardList[r].push({
"index": i,
"number": number,
"editable": true,
"inConflict": false
});
}
i++;
}
}
console.log(JSON.stringify(boardList));

this.state = {boardList};
}

updateNumber(number, index) {
let newBoardList = this.state.boardList;
for (let row = 0; row < 3; row++) {
for (let col = 0; col < 3; col++) {
if (newBoardList[row][col].index === index) {
newBoardList[row][col].number = number;
this.setState({boardList: newBoardList});
}
}
}
}

renderCell(cell, i) {
return (
<Cell key={i} index={cell.index} editable={cell.editable} updateNumberInCell={this.updateNumber}>{cell.number}</Cell>);
}

render() {
return (<div> {/*map means return a new array and do this function for each element in the list*/}
<table>
<tbody>
<tr>
{this.state.boardList[0].map(this.renderCell)}
</tr>
<tr>
{this.state.boardList[1].map(this.renderCell)}
</tr>
<tr>
{this.state.boardList[2].map(this.renderCell)}
</tr>
</tbody>
</table>
</div>
);
}

}


ReactDOM.render(<Board boardString="102840503" />, document.getElementById("sudoku"));

Answer

You are getting this error, because your this reference inside renderCell function is undefined. To get correct this reference in callbacks, you should use bind method.

Working code:

renderCell(cell, i) {
    return (
            <Cell key={i} index={cell.index} editable={cell.editable} updateNumberInCell={this.updateNumber.bind(this)}>{cell.number}</Cell>);
}

render() {
    return (<div>                                                       {/*map means return a new array and do this function for each element in the list*/}
                <table>
                    <tbody>
                    <tr>
                        {this.state.boardList[0].map(this.renderCell.bind(this))}
                    </tr>
                    <tr>
                        {this.state.boardList[1].map(this.renderCell.bind(this))}
                    </tr>
                    <tr>
                        {this.state.boardList[2].map(this.renderCell.bind(this))}
                    </tr>
                    </tbody>
                </table>
            </div>
    );
}

Or you can use bind in constructor instead:

constructor(props) {
    super(props);

    this.state = {editing: false};

    this.renderCell = this.renderCell.bind(this);
    this.updateNumber = this.updateNumber.bind(this);
}
Comments