[入門]reactでtodoリストを作成する

調べても、自分が欲している内容のreactチュートリアルがなかったので、自分で作成した。
よくあるtodoリストを作成する。
欲していたのは、以下の内容なので、それを盛り込んだチュートリアルになっている。
・functional componentの使用
・アロー関数の使用
・styled-componentsの使用
atomic design, redux, ts など取り入れたかったが、モリモリになってしまうので、そこは気が向いたら。


<h1>環境構築</h1>
[node](https://nodejs.org/ja/)のinstall

yarnのinstall
```npm i --global yarn```

version確認
```yarn --version```

create-react-app のinstall
```yarn global add create-react-app```
reactアプリの作成
```create-react-app todoApp```
todoApp は作成するディレクトリ名

reactアプリの立ち上げ
```yarn start```

localhost:3000 で画面が表示される。
![スクリーンショット 2021-07-28 22.35.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603181/8b9c7500-b098-057f-82b9-040a90e35fdf.png)

hello worldだけを表示できるか試しに、src/App.js を編集する

```react:src/App.js
import './App.css';

function App() {
	return <div className="App">hello world</div>;
}

export default App;

```
画面を見ると、hello worldとだけ表示されているはず。

コードを書き換えることで、src/App.test.js でエラーがでてしまう。
ここでは、テストファイルを扱わないのでファイルごと削除してしまってよい。

<h1>アロー関数</h1>
src/App.js でコンポーネントの宣言をアロー関数に書き換える。
[アロー関数式(https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Functions/Arrow_functions)

```react:src/App.js
import './App.css';

const App = () => {
	return <div className="App">hello world</div>;
};

export default App;
```
<h1>ヘッダー作成</h1>
Header コンポーネントを作成する。

```react:src/Header.js
const Header = () => {
	return <h1>todo app</h1>;
};

export default Header;
```

HeaderコンポーネントをApp.jsで使用する

```react:src/App.js
import './App.css';
import Header from './Header';

const App = () => {
	return (
		<>
			<Header />
			<div className="App">hello world</div>
		</>
	);
};

export default App;
```
```<></> ``` についてはこちら　https://ja.reactjs.org/docs/fragments.html

画面を見るとヘッダーが表示されるが、スタイルがかかっていないため左によってしまう。
![スクリーンショット 2021-07-28 22.57.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603181/ef4fd7db-9b27-42cb-759e-8d2174b85ea8.png)

<h1>styled-components</h1>
cssはstyled-componentsを使用していく。

styled-componentsのinstall
```yarn add styled components```

styled-componentsを使ってスタイルを定義
styled-componentsについては[こちら](https://gist.github.com/kenmori/60bf7b67819061f41ce960617c035955)

```react:src/Header.js
import styled from 'styled-components';

const Header = () => {
	return <HeaderComponent>todo app</HeaderComponent>;
};

const HeaderComponent = styled.h1`
	text-align: center;
`;

export default Header;
```

ヘッダーが中央による
![スクリーンショット 2021-07-28 23.08.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603181/be5363e6-2a12-f10c-16a3-f59d4ab73b9e.png)


<h1>todoアプリ作成</h1>
todoを入力するフォームを作成する。

```react:src/Form.js
import React from 'react';
import styled from 'styled-components';

const Form = () => {
	return (
		<Component>
			<div>title</div>
			<input name="title" type="text" />
			<div>desc</div>
			<textarea name="desc" type="text" />
		</Component>
	);
};

const Component = styled.div`
	text-align: center;
	margin: 30px auto;
	width: 400px;
	font-weight: bold;
`;

export default Form;
```

titleとdescを入力できるフォームができた。
![スクリーンショット 2021-07-28 23.28.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603181/a9f9aa80-5dce-9c58-7227-72bef216db84.png)

<h1>state</h1>

次に、フォームに今何が入力されている状態なのかをわかるようにstateを使う。

useStateをimportして、inputとtextareaにvalueとonChangeの設定をする。

useStateについては[こちら](https://qiita.com/makkkiy/items/8bd0cf7814248852d7ff)

```react:src/Form.js
import React, { useState } from 'react';
import styled from 'styled-components';

const Form = () => {
	const [title, setTitle] = useState('');
	const [desc, setDesc] = useState('');

	return (
		<Component>
			<div>title</div>
			<input
				name="title"
				type="text"
				value={title}
				onChange={(e) => setTitle(e.target.value)}
			/>
			<div>desc</div>
			<textarea
				name="desc"
				type="text"
				value={desc}
				onChange={(e) => setDesc(e.target.value)}
			/>
		</Component>
	);
};

const Component = styled.div`
	text-align: center;
	margin: 30px auto;
	width: 400px;
	font-weight: bold;
`;

export default Form;
```

試しに、console.log()仕込んでみて、stateに反映されているか確認

```react:src/Form.js
import React, { useState } from 'react';
import styled from 'styled-components';

const Form = () => {
	const [title, setTitle] = useState('');
	const [desc, setDesc] = useState('');
	console.log(title); // あとで消す
	console.log(desc); // あとで消す
	return (
		<Component>
			<div>title</div>
			<input
				name="title"
				type="text"
				value={title}
				onChange={(e) => setTitle(e.target.value)}
			/>
			<div>desc</div>
			<textarea
				name="desc"
				type="text"
				value={desc}
				onChange={(e) => setDesc(e.target.value)}
			/>
		</Component>
	);
};

const Component = styled.div`
	text-align: center;
	margin: 30px auto;
	width: 400px;
	font-weight: bold;
`;

export default Form;
```

何か入力するたびに、consoleにログがはかれるはず。

<h1>onClickで登録処理</h1>

次に、todoを登録。登録したtodoを表示する処理

まず、登録ボタンを作成し、onClickにクリックした時の処理を記述した関数を渡す。
処理内容は、
・todoを登録
・formを空にする
の2つだが、まだtodoの登録先を作っていないので、一旦formを空にする処理だけ記述。

```react:src/Form.js
import React, { useState } from 'react';
import styled from 'styled-components';

const Form = () => {
	const [title, setTitle] = useState('');
	const [desc, setDesc] = useState('');

	const handleSubmit = (e) => {
		e.preventDefault();
		// 入力formを空にする
		setTitle('');
		setDesc('');
	};

	return (
		<Component>
			<div>title</div>
			<input
				name="title"
				type="text"
				value={title}
				onChange={(e) => setTitle(e.target.value)}
			/>
			<div>desc</div>
			<textarea
				name="desc"
				type="text"
				value={desc}
				onChange={(e) => setDesc(e.target.value)}
			/>
			<br />
			<button onClick={handleSubmit}>todoを作成</button>
		</Component>
	);
};

const Component = styled.div`
	text-align: center;
	margin: 30px auto;
	width: 400px;
	font-weight: bold;
`;

export default Form;

```

titleとdescに文字を入力してからtodoを作成を押すと、入力フォームが空になるはず。
![スクリーンショット 2021-07-29 0.21.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603181/89964e4e-e029-6e39-781e-99de334a9bcd.png)

<h1>propsで登録処理の関数を渡す</h1>
todoの登録先はstateを使う。
todoリストに登録していくために、登録処理の関数を作成し、propsでFormコンポーネントに渡す。

```react:App.js
import React, { useState } from 'react';
import Header from './Header';
import Form from './Form';

const App = () => {
	// 登録されたtodoリスト
	const [todos, setTodos] = useState([
		{ id: 0, title: `やること`, desc: 'やることの説明' },
	]);
	// todoのユニークid
	const [id, setId] = useState(1);
	// todosに入力されたtodoを登録する処理
	const addTodo = (todo) => {
		setTodos([...todos, { id, title: todo.title, desc: todo.desc }]);
		setId(id + 1);
	};
	return (
		<>
			<Header />
			<Form addTodo={addTodo} />
		</>
	);
};

export default App;
```

Form.jsでaddTodoを使ってtodoリストに登録させる

```react:src/Form.js
import React, { useState } from 'react';
import styled from 'styled-components';

const Form = (props) => {
	const [title, setTitle] = useState('');
	const [desc, setDesc] = useState('');

	const handleSubmit = (e) => {
		e.preventDefault();
		// todoListに登録する
		props.addTodo({ title, desc });
		// 入力formを空にする
		setTitle('');
		setDesc('');
	};

	return (
		<Component>
			<div>title</div>
			<input
				name="title"
				type="text"
				value={title}
				onChange={(e) => setTitle(e.target.value)}
			/>
			<div>desc</div>
			<textarea
				name="desc"
				type="text"
				value={desc}
				onChange={(e) => setDesc(e.target.value)}
			/>
			<br />
			<button onClick={handleSubmit}>todoを作成</button>
		</Component>
	);
};

const Component = styled.div`
	text-align: center;
	margin: 30px auto;
	width: 400px;
	font-weight: bold;
`;

export default Form;
```

<h1>todoリストをmapを使用して表示</h1>

これだけでは、本当に登録されているか分からないので、
登録されたtodoを表示するコンポーネントを作成する。
propsで受け取ったtodoリストを表示する。
mapを使用して、リスト分作成していく。
その際、keyを指定すること。
mapとkeyについては[こちら](https://ja.reactjs.org/docs/lists-and-keys.html)

```react:TodoList.js
import React from 'react';

const TodoList = (props) => {
	return (
		<ul>
			{props.todos.map((todo) => (
				<li key={todo.id}>
					<span>{todo.title}</span>
					<br />
					<p>{todo.desc}</p>
				</li>
			))}
		</ul>
	);
};

export default TodoList;
```

App.jsでTodoListコンポーネントにtodosを渡す。

```react:src/App.js
import React, { useState } from 'react';
import Header from './Header';
import Form from './Form';
import TodoList from './TodoList';

const App = () => {
	// 登録されたtodoリスト
	const [todos, setTodos] = useState([
		{ id: 0, title: `やること`, desc: 'やることの説明' },
	]);
	// todoのユニークid
	const [id, setId] = useState(1);
	// todosに入力されたtodoを登録する処理
	const addTodo = (todo) => {
		setTodos([...todos, { id, title: todo.title, desc: todo.desc }]);
		setId(id + 1);
	};

	return (
		<>
			<Header />
			<Form addTodo={addTodo} />
			<TodoList todos={todos} />
		</>
	);
};

export default App;
```

入力フォームに文字を入れて、ボタンを押すとページ下部にtodoが追加されていく。
![スクリーンショット 2021-07-29 0.48.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603181/9dce7703-03b6-7d05-e3c8-1babe6356e91.png)

細かく書くのは一旦ここまで。気が向いたら追記します。
想定していることは、
・todoが完了したことがわかるように、完了ボタン用意。
・CRUDで言うと、todoを更新、削除できるような処理。
・styeld-components使っておきながら、全然スタイル定義していないので、スタイル整えるのも。
・コンポーネントの切り分け。保守性・拡張性無視しているので、atomic desgin を意識した構成にリファクタ。
・tsの取り込み。(todoリストのオブジェクトの型がないのが気持ち悪い)
・reduxの取り込み。(redux使うほどの規模ではないから難しいかも)