この記事の概要
TODOアプリをコンポーネント化していく記事です。
どちらかと言えばReactの経験が浅い人向けの記事です。
コンポーネント化の参考にしてください。
コンポーネント化
まずはsrcフォルダからcomponentsディレクトリを作ります。
そこから何かしらのjsxのファイルを作ります。
追加部分をコンポーネント化
Input.jsx
import React from "react";
export const Input = (props) => { //propsを使う
const { todoText, onChange, onClickAdd } = props;
return (
<div className="input-area">
<input placeholder="入力" value={todoText} onChange={onChange} />
<button onClick={onClickAdd}>追加</button>
</div>
);
};
App.jsx
import React, { useState } from "react";
import "./styles.css";
import { Input } from "./components/Input";
export const App = () => {
const [todoText, setTodoText] = useState(""); //配列初期化
const [incompleteTodo, setIncompleteTodo] = useState([]); //配列初期化
const [completeTodo, setCompleteTodo] = useState([]); //配列初期化
const onChangeTodoText = (event) => setTodoText(event.target.value);
const onClickAdd = () => {
if (todoText === "") return; //テキストが空だったらリターン 何も入力しなければ追加できないようにする
const newTodo = [...incompleteTodo, todoText];
setIncompleteTodo(newTodo); //未完了リスト追加
setTodoText(); //空文字設定
//alert(todoText); //処理が通っているかalertで確認
};
const clickDelete = (index) => {
const newTodo = [...incompleteTodo];
newTodo.splice(index, 1); //1つ目の引数に何番目の要素かを受け取り2つ目の要素にいくつ削除するか
setIncompleteTodo(newTodo); //未完了todo更新
//alert("削除");
//alert(index);
};
const clickComplete = (index) => {
const newIncompleteTodo = [...incompleteTodo];
newIncompleteTodo.splice(index, 1);
//alert(index); //アラートで確認
const newCompleteTodo = [...completeTodo, incompleteTodo[index]];
setIncompleteTodo(newIncompleteTodo);
setCompleteTodo(newCompleteTodo);
};
//戻す機能
const clickBack = (index) => {
const newCompleteTodo = [...completeTodo]; //完了エリア削除
newCompleteTodo.splice(index, 1);
const newIncompleteTodo = [...incompleteTodo, completeTodo[index]];
setCompleteTodo(newCompleteTodo);
setIncompleteTodo(newIncompleteTodo);
};
return (
<>
<InputTodo //propsとして渡す
todoText={todoText} //propsとして渡す
onChange={onChangeTodoText} //propsとして渡す
onClickAdd={onClickAdd} //propsとして渡す
/>
<div className="incomplete-area">
<p className="title">未完了</p>
<ul>
{incompleteTodo.map((todo, index) => {
return (
<div key={todo} className="list-row">
<li>{todo}</li>
<button onClick={() => clickComplete(index)}>完了</button>
<button onClick={() => clickDelete(index)}>削除</button>
</div>
);
})}
</ul>
</div>
<div className="complte-area">
<p className="title">完了</p>
<ul>
{completeTodo.map((todo, index) => {
return (
<div key={todo} className="list-row">
<li>{todo}</li>
<button onClick={() => clickBack(index)}>戻す</button>
</div>
);
})}
</ul>
</div>
</>
);
};
未完了部分をコンポーネント化
まずはsrcフォルダからcomponentsディレクトリを作ります。
そこから何かしらのjsxのファイルを作ります。
Incomplete.jsx
import React from "react";
export const Incomplete = (props) => {
const { todo, clickComplete, clickDelete } = props;
return (
<div className="incomplete-area">
<p className="title">未完了</p>
<ul>
{todo.map((todo, index) => { //todoに変更
return (
<div key={todo} className="list-row">
<li>{todo}</li>
<button onClick={() => clickComplete(index)}>完了</button>
<button onClick={() => clickDelete(index)}>削除</button>
</div>
);
})}
</ul>
</div>
);
};
App.jsx
import React, { useState } from "react";
import "./styles.css";
import { InputTodo } from "./components/Input";
import { IncompleteTodo } from "./components/Incomplete"; //import追記
export const App = () => {
const [todoText, setTodoText] = useState(""); //配列初期化
const [incompleteTodo, setIncompleteTodo] = useState([]); //配列初期化
const [completeTodo, setCompleteTodo] = useState([]); //配列初期化
const onChangeTodoText = (event) => setTodoText(event.target.value);
const onClickAdd = () => {
if (todoText === "") return; //テキストが空だったらリターン 何も入力しなければ追加できないようにする
const newTodo = [...incompleteTodo, todoText];
setIncompleteTodo(newTodo); //未完了リスト追加
setTodoText(); //空文字設定
//alert(todoText); //処理が通っているかalertで確認
};
const clickDelete = (index) => {
const newTodo = [...incompleteTodo];
newTodo.splice(index, 1); //1つ目の引数に何番目の要素かを受け取り2つ目の要素にいくつ削除するか
setIncompleteTodo(newTodo); //未完了todo更新
//alert("削除");
//alert(index);
};
const clickComplete = (index) => {
const newIncompleteTodo = [...incompleteTodo];
newIncompleteTodo.splice(index, 1);
//alert(index); //アラートで確認
const newCompleteTodo = [...completeTodo, incompleteTodo[index]];
setIncompleteTodo(newIncompleteTodo);
setCompleteTodo(newCompleteTodo);
};
//戻す機能
const clickBack = (index) => {
const newCompleteTodo = [...completeTodo]; //完了エリア削除
newCompleteTodo.splice(index, 1);
const newIncompleteTodo = [...incompleteTodo, completeTodo[index]];
setCompleteTodo(newCompleteTodo);
setIncompleteTodo(newIncompleteTodo);
};
return (
<>
<InputTodo
todoText={todoText}
onChange={onChangeTodoText}
onClickAdd={onClickAdd}
/>
//未完了追記
<IncompleteTodo
todo={incompleteTodo}
clickComplete={clickComplete}
clickDelete={clickDelete}
/>
<div className="complte-area">
<p className="title">完了</p>
<ul>
{completeTodo.map((todo, index) => {
return (
<div key={todo} className="list-row">
<li>{todo}</li>
<button onClick={() => clickBack(index)}>戻す</button>
</div>
);
})}
</ul>
</div>
</>
);
};
完了部分をコンポーネント化
まずはsrcフォルダからcomponentsディレクトリを作ります。
そこから何かしらのjsxのファイルを作ります。
Complete.jsx
import React from "react";
export const Complete = (props) => {
const { todo, clickBack } = props;
return (
<div className="complte-area">
<p className="title">完了</p>
<ul>
{todo.map((todo, index) => {
return (
<div key={todo} className="list-row">
<li>{todo}</li>
<button onClick={() => clickBack(index)}>戻す</button>
</div>
);
})}
</ul>
</div>
);
};
App.jsx
import React, { useState } from "react";
import "./styles.css";
import { InputTodo } from "./components/InputTodo";
import { IncompleteTodo } from "./components/IncompleteTodo";
import { Complete } from "./components/Complete"; //Completeをインポート
export const App = () => {
const [todoText, setTodoText] = useState(""); //配列初期化
const [incompleteTodo, setIncompleteTodo] = useState([]); //配列初期化
const [completeTodo, setCompleteTodo] = useState([]); //配列初期化
const onChangeTodoText = (event) => setTodoText(event.target.value);
//追加機能
const onClickAdd = () => {
if (todoText === "") return; //テキストが空だったらリターン 何も入力しなければ追加できないようにする
const newTodo = [...incompleteTodo, todoText];
setIncompleteTodo(newTodo); //未完了リスト追加
setTodoText(); //空文字設定
//alert(todoText); //処理が通っているかalertで確認
};
//完了機能
const clickDelete = (index) => {
const newTodo = [...incompleteTodo];
newTodo.splice(index, 1); //1つ目の引数に何番目の要素かを受け取り2つ目の要素にいくつ削除するか
setIncompleteTodo(newTodo); //未完了todo更新
//alert("削除");
//alert(index);
};
const clickComplete = (index) => {
const newIncompleteTodo = [...incompleteTodo];
newIncompleteTodo.splice(index, 1);
//alert(index); //アラートで確認
const newCompleteTodo = [...completeTodo, incompleteTodo[index]];
setIncompleteTodo(newIncompleteTodo);
setCompleteTodo(newCompleteTodo);
};
//戻す機能
const clickBack = (index) => {
const newCompleteTodo = [...completeTodo]; //完了エリア削除
newCompleteTodo.splice(index, 1);
const newIncompleteTodo = [...incompleteTodo, completeTodo[index]];
setCompleteTodo(newCompleteTodo);
setIncompleteTodo(newIncompleteTodo);
};
return (
<>
<InputTodo
todoText={todoText}
onChange={onChangeTodoText}
onClickAdd={onClickAdd}
/>
<IncompleteTodo
todo={incompleteTodo}
clickComplete={clickComplete}
clickDelete={clickDelete}
/>
<Complete todo={completeTodo} clickBack={clickBack} /> //コンポーネント化
</>
);
};
CSS-in-JSとは
Reactでコンポーネント分割した時に、CSSをコンポーネント化したJavaScriptに書いて
管理することです。
実際に書いてみる
まずはCSSのファイルです。
Styles.css
.input-area {
background-color: aqua;
width: 400px;
height: 30px;
padding: 8px;
margin: 8px;
border-radius: 8px;
}
これをInPut.jsxに書いていきます。
InPut.jsx
import React from "react";
//書き方はJavaScript
const style = {
backgroundColor: "#00ffff",
width: "400px",
height: "30px",
padding: "8px",
margin: "8px",
borderRadius: "8px"
};
export const InputTodo = (props) => {
const { todoText, onChange, onClickAdd } = props;
return (
<div style={style} className="input-area"> //styleを追記
<input placeholder="入力" value={todoText} onChange={onChange} />
<button onClick={onClickAdd}>追加</button>
</div>
);
};
style.cssのコピーした部分のinput-areaは削除しても大丈夫です。
資料