コンポーネント化とは
機能ごとに分割して別ファイルにしておくことで、使い回せたり、状態の管理もしやすく拡張性があるので再利用も容易にできるというメリットがあります。
前提
-
CodeSandbox
を使用
実装手順
実装順 | ページ内リンク |
---|---|
1 | コンポーネント用のディレクトリ作成 |
2 | テキストボックス |
3 | 未完了TODOリスト |
4 | 完了TODOリスト |
コンポーネント用のディレクトリ作成
-
src
ディレクト配下にcomponents
ディレクトリを作成- これから作成するコンポーネントファイルは、このディレクトリに格納します。
テキストボックス
まずは、タスクの入力欄であるテキストボックスからコンポーネント化していきます。
src/components/InputTodo.jsx
import React from "react";
export const InputTodo = (props) => {
const { todoText, onChange, onClick } = props;
return (
<div className="input-area">
<input placeholder="TODOを入力" value={todoText} onChange={onChange} />
<button onClick={onClick}>追加</button>
</div>
);
};
- テキストボックス用のコンポーネントファイル(
InpotTodo.jsx
)を作成し、src/App.jsx
からテキストボックス部分のコードをコピ-し、貼り付けてから修正を行なっています。
export const InputTodo = (props) => {
const { todoText, onChange, onClick } = props;
- 親コンポーネント(
src/App.jsx
)に記述のある関数をprops
を用いて受け取っています。- 分割代入を使用することで、受け取った
props
の先頭にprops.
と書く必要がなくなるため、記述量が減り、コードの見通しが良くなります。
- 分割代入を使用することで、受け取った
<button onClick={onClick}>追加</button>
// 分割代入せずに使用する場合
<button onClick={props.onClick}>追加</button>
-
props
で受け取った関数を使用しています。
src/App.jsx
import React, { useState } from "react";
import "./styles.css";
import { InputTodo } from "./components/InputTodo";
export const App = () => {
const [todoText, setTodoText] = useState("");
const [incompleteTodos, setIncompleteTodos] = useState([]);
const [completeTodos, setCompleteTodos] = useState([]);
const onChangeTodoText = (event) => setTodoText(event.target.value);
const onClickAdd = () => {
if (todoText === "") return;
const newTodos = [...incompleteTodos, todoText];
setIncompleteTodos(newTodos);
setTodoText("");
};
.
.
.
return (
<>
<InputTodo
todoText={todoText}
onChange={onChangeTodoText}
onClick={onClickAdd}
/>
.
.
.
次に親コンポーネントであるApp.jsx
ファイルを編集します。
import { InputTodo } from "./components/InputTodo";
- コンポーネント化した
InputTodo
ファイルのインポートを宣言します。
<InputTodo
todoText={todoText}
onChange={onChangeTodoText}
onClick={onClickAdd}
/>
- 先ほどコピーしたテキストボックス部分のコードを削除し、
<InputTodo />
に置き換えることでコンポーネントを呼び出すことができます。 - コンポーネント内には、
Input.jsx
に関数を渡すための記述をしています。-
porps
(任意の名前)に関数を代入しています ->props名={関数名}
-
JavaScript
を渡すのでブランケット{}
で関数を囲っています。
-
-
未完了リスト
次に未完了TODOリスト欄をコンポーネント化していきます。
src/components/IncompleteTodos.jsx
import React from "react";
export const IncompleteTodos = (props) => {
const { todos, onClickComplete, onClickDelete } = props;
return (
<div className="incomplete-area">
<p className="title">未完了のTODO</p>
<ul>
{todos.map((todo, index) => {
return (
<div key={todo} className="list-row">
<li>{todo}</li>
<button onClick={() => onClickComplete(index)}>完了</button>
<button onClick={() => onClickDelete(index)}>削除</button>
</div>
);
})}
</ul>
</div>
);
};
src/App.jsx
import React, { useState } from "react";
import "./styles.css";
import { InputTodo } from "./components/InputTodo";
import { IncompleteTodos } from "./components/IncompleteTodos"; // 追加
export const App = () => {
.
.
.
const onClickDelete = (index) => {
const newTodos = [...incompleteTodos];
newTodos.splice(index, 1);
setIncompleteTodos(newTodos);
};
const onClickComplete = (index) => {
const newIncompleteTodos = [...incompleteTodos];
newIncompleteTodos.splice(index, 1);
setIncompleteTodos(newIncompleteTodos);
const newCompleteTodos = [...completeTodos, incompleteTodos[index]];
setCompleteTodos(newCompleteTodos);
};
.
.
.
return (
<>
.
.
.
<IncompleteTodos
todos={incompleteTodos}
onClickComplete={onClickComplete}
onClickDelete={onClickDelete}
/>
先ほどと同様の実装のため、解説は割愛します。
完了リスト
最後に完了TODOリスト欄をコンポーネント化していきます。
src/components/IncompleteTodos.jsx
import React from "react";
export const CompleteTodos = (props) => {
const { todos, onClickBack } = props;
return (
<div className="complete-area">
<p className="title">完了のTODO</p>
<ul>
{todos.map((todo, index) => {
return (
<div key={todo} className="list-row">
<li>{todo}</li>
<button onClick={() => onClickBack(index)}>戻る</button>
</div>
);
})}
</ul>
</div>
);
};
src/App.jsx
import React, { useState } from "react";
import "./styles.css";
import { InputTodo } from "./components/InputTodo";
import { IncompleteTodos } from "./components/IncompleteTodos";
import { CompleteTodos } from "./components/CompleteTodos"; // 追加
export const App = () => {
.
.
.
const [completeTodos, setCompleteTodos] = useState([]);
.
.
.
const onClickBack = (index) => {
const newCompleteTodos = [...completeTodos];
newCompleteTodos.splice(index, 1);
setCompleteTodos(newCompleteTodos);
.
.
.
return (
<>
.
.
.
<CompleteTodos todos={completeTodos} onClickBack={onClickBack} />
先ほどと同様の実装のため、解説は割愛します。
完成形のソースコード
src/App.jsx
import React, { useState } from "react";
import "./styles.css";
import { InputTodo } from "./components/InputTodo";
import { IncompleteTodos } from "./components/IncompleteTodos";
import { CompleteTodos } from "./components/CompleteTodos";
export const App = () => {
const [todoText, setTodoText] = useState("");
const [incompleteTodos, setIncompleteTodos] = useState([]);
const [completeTodos, setCompleteTodos] = useState([]);
const onChangeTodoText = (event) => setTodoText(event.target.value);
const onClickAdd = () => {
if (todoText === "") return;
const newTodos = [...incompleteTodos, todoText];
setIncompleteTodos(newTodos);
setTodoText("");
};
const onClickDelete = (index) => {
const newTodos = [...incompleteTodos];
newTodos.splice(index, 1);
setIncompleteTodos(newTodos);
};
const onClickComplete = (index) => {
const newIncompleteTodos = [...incompleteTodos];
newIncompleteTodos.splice(index, 1);
setIncompleteTodos(newIncompleteTodos);
const newCompleteTodos = [...completeTodos, incompleteTodos[index]];
setCompleteTodos(newCompleteTodos);
};
const onClickBack = (index) => {
const newCompleteTodos = [...completeTodos];
newCompleteTodos.splice(index, 1);
setCompleteTodos(newCompleteTodos);
const newIncompleteTodos = [...incompleteTodos, completeTodos[index]];
setIncompleteTodos(newIncompleteTodos);
};
return (
<>
<InputTodo
todoText={todoText}
onChange={onChangeTodoText}
onClick={onClickAdd}
/>
<IncompleteTodos
todos={incompleteTodos}
onClickComplete={onClickComplete}
onClickDelete={onClickDelete}
/>
<CompleteTodos todos={completeTodos} onClickBack={onClickBack} />
</>
);
};
このようにコンポーネント化したことでreturn();
内のHTML部分がスッキリとしてコードの見通しが良くなったことが分かります。
最後に
実はじゃけぇさんが提供しているもう一本の教材も購入しています笑
中級者レベルと難易度も上がっているので、学習しながらステップアップしちゃいます!