todoapp.tsx
import React, { Component, MouseEvent, ChangeEvent } from 'react';
type Item = {
name: string;
completed: boolean;
};
interface TodoState {
items: Item[]; // existing items
newName: string; // text in the field to add a new name
}
export class ToDoApp extends Component<{}, TodoState> {
constructor(props: {}) {
super(props);
this.state = { items: [], newName: "" };
}
// Called when the user checks the box next to an uncompleted item. The
// second parameter is the index of that item in the list.
completeItem = (_: ChangeEvent<HTMLInputElement>, index: number): void => {
const items = this.state.items.slice(0);
items[index] = {name: items[index].name, completed: true};
this.setState({items: items});
setTimeout(() => this.removeItem(index), 500);
}
// Removes the item at the given index
removeItem = (index: number): void => {
const items = this.state.items.slice(0);
items.splice(index, 1);
this.setState({items: items});
}
// Called when the user clicks on the button to add the new item.
addItem = (_: MouseEvent<HTMLButtonElement>): void => {
const name = this.state.newName.trim().replace('\t', ' '); // no tabs
if (name.length > 0) {
const items = this.state.items.slice(0);
items.push({name: name, completed: false});
this.setState({items: items, newName: ""});
}
}
// Called each time the text in the new item name field is changed.
setNewName = (evt: ChangeEvent<HTMLInputElement>): void => {
this.setState({newName: evt.target.value});
}
render = (): JSX.Element => {
const items: JSX.Element[] = [];
for (let i = 0; i < this.state.items.length; i++) {
if (this.state.items[i].completed) {
items.push(
<div className="form-check" key={i}>
<input className="form-check-input" type="checkbox"
id={"check" + i} checked={true} readOnly={true} />
<label className="form-check-label completed" htmlFor={"check" + i}>
{this.state.items[i].name}
</label>
</div>);
} else {
items.push(
<div className="form-check" key={i}>
<input className="form-check-input" type="checkbox"
id={"check" + i} checked={false}
onChange={evt => this.completeItem(evt, i)} />
<label className="form-check-label" htmlFor={"check" + i}>
{this.state.items[i].name}
</label>
</div>);
}
}
return (
<div>
<h2>To-Do List</h2>
{items}
<p className="instructions">Check the item to mark it completed.</p>
<p className="more-instructions">New item:
<input type="text" className="new-item"
value={this.state.newName}
onChange={this.setNewName} />
<button type="button" className="btn btn-link"
onClick={this.addItem}>Add</button>
</p>
</div>);
}
}
Full Code