The file we should focus now is App.js. This file out of the box contains the following code:
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
class App extends Component {
render() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h1 className="App-title">Welcome to React</h1>
</header>
<p className="App-intro">
To get started, edit <code>src/App.js</code> and
save to reload.
</p>
</div>
);
}
}
export default App;
Let’s wipe out the bulk of this code and just replace it with a simple render of the Table component (which we’ll implement next).
We pass it 2 properties: x
the number of columns and y
the number of rows.
import React from 'react'
import Table from './components/Table'
const App = () =>
(<div style={{ width: 'max-content' }}>
<Table x={4} y={4} />
</div>)
export default App
Here’s the Table component, which we store in components/Table.js
:
import React from 'react'
import Row from './Row'
export default class Table extends React.Component {
constructor(props) {
super(props)
this.state = {
data: {},
}
}
handleChangedCell = ({ x, y }, value) => {
const modifiedData = Object.assign({}, this.state.data)
if (!modifiedData[y]) modifiedData[y] = {}
modifiedData[y][x] = value
this.setState({ data: modifiedData })
}
updateCells = () => {
this.forceUpdate()
}
render() {
const rows = []
for (let y = 0; y < this.props.y + 1; y += 1) {
const rowData = this.state.data[y] || {}
rows.push(
<Row
handleChangedCell={this.handleChangedCell}
updateCells={this.updateCells}
key={y}
y={y}
x={this.props.x + 1}
rowData={rowData}
/>,
)
}
return (
<div>
{rows}
</div>
)
}
}
The Table
component manages its own state. Its render()
method creates a list of Row
components, and passes to each one the part of state that bothers them: the row data. The Row component will in turn pass this data down to multiple Cell
components, which we’ll introduce in a minute.
We use the y
row number as the key property, which is mandatory to distinguish multiple rows.
We pass to each Row
component the handleChangedCell
method as a prop. When a row calls this method, it passes an (x, y)
tuple indicating the row, and the new value that’s been inserted into it, and we update the state accordingly.