0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Reactでコンポーネント化のやり方とコンポーネントした時に使うCSS-in-JS

Last updated at Posted at 2023-02-16

この記事の概要

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は削除しても大丈夫です。

資料

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?