create-react-app
create-react-appでアプリを作成した。 TypeScriptを有効にしている。
$ npx create-react-app react-todo-unstated --typescript
$ cd react-todo-unstated
$ tree src/
src/
├── App.css
├── App.test.tsx
├── App.tsx
├── index.css
├── index.tsx
├── logo.svg
├── react-app-env.d.ts
└── serviceWorker.ts
$ npm start
Material-UI
UIはMaterial-UIでUIで作った。
$ npm install --save @material-ui/core @material-ui/icons
public/index.html
にRobotoフォントを入れた。
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500">
Unstated
UnstatedはReact v16からのContext APIを使ったStateを管理するための薄いライブラリ。
$ npm install --save unstated
Stateを持つContainerを作る。
class TodoContainer extends Container<TodoState> {
state: TodoState = {
newTodo: "",
todos: [],
isCreating: false
};
changeNewTodo(newTodo: string) {
this.setState({ newTodo: newTodo });
}
async createTodo() {
if (!this.canCreateTodo()) {
return
}
this.setState({ isCreating: true });
const newTodo = { title: this.state.newTodo, isDone: false }
await axios.post<Todo[]>("http://localhost:3001/todo", newTodo)
await this.loadTodo()
this.setState({ newTodo: "", isCreating: false })
}
canCreateTodo() {
return this.state.newTodo.length !== 0 && !this.state.isCreating
}
async setIsDone(id: number, status: boolean) {
const target = this.state.todos.find((t) => t.id === id)
if (target) {
target.isDone = status
await axios.put<Todo[]>(`http://localhost:3001/todo/${id}`, target)
await this.loadTodo()
}
}
async deleteTodo(id: number) {
await axios.delete(`http://localhost:3001/todo/${id}`)
await this.loadTodo()
}
async loadTodo() {
const resp = await axios.get<Todo[]>("http://localhost:3001/todo")
this.setState({ todos: resp.data })
}
}
<Provider>
の中で<Subscript to={[Container]}>
するとContainerが渡ってくるので、
このstateにアクセスしたりメソッドを呼んでstateを更新でき、変更があったら再レンダリングされる。
<Provider>
...
<div className="App">
<div className="Form"><TodoForm></TodoForm></div>
<div className="Chart"><DoneChart></DoneChart></div>
<TodoList></TodoList>
</div>
</Provider>
# <DoneChart>
<Subscribe to={[TodoContainer]}>
{(container: TodoContainer) =>
<PieChart width={200} height={200}>
<Pie data={this.data(container).data} dataKey="value" innerRadius={60} outerRadius={80}>
{
this.data(container).data.map(d => <Cell fill={d.color} />)
}
</Pie>
<text x={100} y={105} textAnchor="middle">{this.data(container).ratio}</text>
</PieChart>
}
</Subscribe>
Recharts
Rechartsでグラフを描いた。
$ npm install --save recharts @types/recharts
<PieChart width={200} height={200}>
<Pie data={this.data(container).data} dataKey="value" innerRadius={60} outerRadius={80}>
{
this.data(container).data.map(d => <Cell fill={d.color} />)
}
</Pie>
<text x={100} y={105} textAnchor="middle">{this.data(container).ratio}</text>
</PieChart>