Reactで学ぶ!配列の基本操作と応用テクニック

Reactは、モダンなWebアプリケーション開発で広く使われているライブラリであり、動的なデータの操作が非常に重要です。その中でも、配列操作はデータを効率的に管理し、表示する上で欠かせない技術です。本記事では、Reactを使って配列を操作するための基本的な方法から応用例までをわかりやすく解説します。初心者から中級者まで、配列操作を習得することでReactアプリケーションの実装力を向上させましょう。

目次

配列とは何か


配列は、複数のデータを一つの変数に格納するためのデータ構造です。JavaScriptにおける配列は、他の多くのプログラミング言語と同様に順序付きのリストとして機能します。配列には、数値、文字列、オブジェクト、関数など、さまざまなデータ型を格納できます。

JavaScriptでの配列の基本


JavaScriptでは、配列を以下のように作成します:

const fruits = ["Apple", "Banana", "Cherry"];
console.log(fruits[0]); // Apple

上記の例では、fruits配列に3つの要素が格納され、fruits[0]で最初の要素にアクセスしています。

配列の主な特徴

  1. インデックスによるアクセス:配列の要素は0から始まるインデックスでアクセスできます。
  2. 可変長:配列の要素数は動的に増減できます。
  3. 多様なデータ型の混在:配列には異なるデータ型を同時に格納できます。
const mixedArray = [42, "Hello", true];
console.log(mixedArray); // [42, "Hello", true]

Reactと配列の関係


Reactでは、配列がコンポーネントでデータを扱う際の重要な役割を果たします。特に、リストをレンダリングする場合や動的にデータを操作する場合に欠かせないため、配列の基本を理解することはReact開発の第一歩となります。

Reactで配列をレンダリングする方法

配列をReactコンポーネント内でレンダリングすることは、動的なリスト表示において非常に重要なスキルです。以下では、Reactで配列を画面に表示する基本的な手法を解説します。

配列データをReactでレンダリングする基本


Reactでは、配列のデータをmapメソッドを使ってJSX要素に変換し、レンダリングします。例えば、文字列の配列をリスト表示する場合、次のように記述します:

import React from 'react';

const FruitsList = () => {
  const fruits = ["Apple", "Banana", "Cherry"];

  return (
    <ul>
      {fruits.map((fruit, index) => (
        <li key={index}>{fruit}</li>
      ))}
    </ul>
  );
};

export default FruitsList;

コード解説

  1. mapメソッド:配列の各要素に対して指定した処理を実行し、新しい配列を生成します。ここでは、各フルーツを<li>要素に変換しています。
  2. key属性:リストをレンダリングする際に、要素に固有のkeyを設定する必要があります。これにより、Reactはリストを効率的に更新できます。
  3. JSX内での式評価{}内でmapを使い、JSXを動的に生成しています。

オブジェクト配列のレンダリング


配列がオブジェクトを含む場合でも同様にレンダリングできます。以下の例では、オブジェクト配列を表示します:

const FruitsListWithDetails = () => {
  const fruits = [
    { id: 1, name: "Apple", color: "Red" },
    { id: 2, name: "Banana", color: "Yellow" },
    { id: 3, name: "Cherry", color: "Red" },
  ];

  return (
    <ul>
      {fruits.map((fruit) => (
        <li key={fruit.id}>
          {fruit.name} - {fruit.color}
        </li>
      ))}
    </ul>
  );
};

コード解説

  • オブジェクトのプロパティアクセスfruit.namefruit.colorのように、オブジェクトのプロパティにアクセスして内容を表示しています。
  • 一意のkey:オブジェクト内のidkeyとして使用することで、レンダリングの効率性を確保しています。

条件付きレンダリング


配列の要素に応じて条件付きで要素をレンダリングすることも可能です。例えば、色が赤い果物だけを表示する場合:

const RedFruitsList = () => {
  const fruits = [
    { id: 1, name: "Apple", color: "Red" },
    { id: 2, name: "Banana", color: "Yellow" },
    { id: 3, name: "Cherry", color: "Red" },
  ];

  return (
    <ul>
      {fruits
        .filter((fruit) => fruit.color === "Red")
        .map((fruit) => (
          <li key={fruit.id}>{fruit.name}</li>
        ))}
    </ul>
  );
};

コード解説

  • filterメソッド:特定の条件に合致する要素のみを抽出します。
  • 組み合わせfiltermapを組み合わせることで、条件付きレンダリングを簡単に実現できます。

まとめ


Reactで配列をレンダリングするには、mapを活用してJSX要素を生成し、key属性で一意性を確保することが基本です。また、配列操作メソッドを組み合わせることで、より柔軟な表示が可能になります。次は、配列の状態管理について学び、動的に更新する方法を理解しましょう。

配列の状態管理

Reactで配列データを管理する場合、状態管理フックであるuseStateを使用します。ここでは、配列を動的に追加、削除、更新する方法を具体例とともに解説します。

配列を状態として管理する基本


useStateを使って配列を管理する基本例を示します:

import React, { useState } from 'react';

const FruitsManager = () => {
  const [fruits, setFruits] = useState(["Apple", "Banana"]);

  const addFruit = () => {
    setFruits([...fruits, "Cherry"]);
  };

  return (
    <div>
      <ul>
        {fruits.map((fruit, index) => (
          <li key={index}>{fruit}</li>
        ))}
      </ul>
      <button onClick={addFruit}>Add Cherry</button>
    </div>
  );
};

export default FruitsManager;

コード解説

  1. useStateの利用fruitsという配列を状態として管理します。初期値として["Apple", "Banana"]を設定しています。
  2. スプレッド構文で配列を更新setFruits([...fruits, "Cherry"])で既存の配列に新しい要素を追加しています。スプレッド構文...を使うことで、元の配列を変更せずに新しい配列を生成します。
  3. 動的レンダリング:状態が変化するたびにmapによるレンダリングが更新されます。

配列要素を削除する方法


特定の要素を削除するには、filterメソッドを活用します:

const removeFruit = (fruitToRemove) => {
  setFruits(fruits.filter((fruit) => fruit !== fruitToRemove));
};

完全なコード例

const FruitsManager = () => {
  const [fruits, setFruits] = useState(["Apple", "Banana", "Cherry"]);

  const removeFruit = (fruitToRemove) => {
    setFruits(fruits.filter((fruit) => fruit !== fruitToRemove));
  };

  return (
    <div>
      <ul>
        {fruits.map((fruit, index) => (
          <li key={index}>
            {fruit} <button onClick={() => removeFruit(fruit)}>Remove</button>
          </li>
        ))}
      </ul>
    </div>
  );
};

配列要素を更新する方法


配列内の特定の要素を更新するには、mapメソッドを利用します:

const updateFruit = (oldFruit, newFruit) => {
  setFruits(fruits.map((fruit) => (fruit === oldFruit ? newFruit : fruit)));
};

完全なコード例

const FruitsManager = () => {
  const [fruits, setFruits] = useState(["Apple", "Banana", "Cherry"]);

  const updateFruit = (oldFruit, newFruit) => {
    setFruits(fruits.map((fruit) => (fruit === oldFruit ? newFruit : fruit)));
  };

  return (
    <div>
      <ul>
        {fruits.map((fruit, index) => (
          <li key={index}>
            {fruit}{" "}
            <button onClick={() => updateFruit(fruit, "UpdatedFruit")}>
              Update
            </button>
          </li>
        ))}
      </ul>
    </div>
  );
};

注意点

  1. 不変性を保つ:Reactの状態管理では、元の配列を直接変更せず、新しい配列を作成して状態を更新することが重要です。
  2. キーの一意性:配列の要素をレンダリングする際にはkeyを一意にすることで、効率的なレンダリングを実現します。

まとめ


useStateを利用することで、配列データを動的に追加、削除、更新することが可能です。不変性を保ちながら状態を管理することが、React開発の効率と品質を高めるポイントです。次は、JavaScriptの配列メソッドを使った基本操作について詳しく学びましょう。

配列操作の基本メソッド

Reactで配列を効率的に扱うためには、JavaScriptが提供する配列操作の基本メソッドを理解することが重要です。本章では、React開発で頻繁に使用されるメソッドとその使い方を具体例とともに解説します。

1. `map` メソッド


配列の各要素に対して指定した処理を実行し、新しい配列を生成します。Reactではリストレンダリングに特に役立ちます。

const numbers = [1, 2, 3];
const doubled = numbers.map((num) => num * 2);
console.log(doubled); // [2, 4, 6]

Reactでの活用例

const fruits = ["Apple", "Banana", "Cherry"];

const FruitsList = () => (
  <ul>
    {fruits.map((fruit, index) => (
      <li key={index}>{fruit}</li>
    ))}
  </ul>
);

2. `filter` メソッド


指定した条件に合致する要素だけを抽出して新しい配列を生成します。

const numbers = [1, 2, 3, 4];
const evenNumbers = numbers.filter((num) => num % 2 === 0);
console.log(evenNumbers); // [2, 4]

Reactでの活用例

const fruits = ["Apple", "Banana", "Cherry", "Avocado"];

const FilteredFruits = () => {
  const filtered = fruits.filter((fruit) => fruit.startsWith("A"));
  return (
    <ul>
      {filtered.map((fruit, index) => (
        <li key={index}>{fruit}</li>
      ))}
    </ul>
  );
};

3. `reduce` メソッド


配列を反復処理して単一の値を生成します。合計値や平均値を計算する際に便利です。

const numbers = [1, 2, 3, 4];
const sum = numbers.reduce((total, num) => total + num, 0);
console.log(sum); // 10

Reactでの活用例

const orders = [
  { item: "Apple", price: 3 },
  { item: "Banana", price: 2 },
  { item: "Cherry", price: 5 },
];

const TotalPrice = () => {
  const total = orders.reduce((sum, order) => sum + order.price, 0);
  return <p>Total Price: ${total}</p>;
};

4. `find` メソッド


配列内の条件に合致する最初の要素を取得します。

const numbers = [1, 2, 3, 4];
const firstEven = numbers.find((num) => num % 2 === 0);
console.log(firstEven); // 2

Reactでの活用例

const fruits = ["Apple", "Banana", "Cherry"];

const FindFruit = () => {
  const cherry = fruits.find((fruit) => fruit === "Cherry");
  return <p>Found: {cherry}</p>;
};

5. `sort` メソッド


配列の要素を並び替えます。デフォルトでは文字列順ですが、カスタムの比較関数を指定できます。

const numbers = [4, 2, 3, 1];
numbers.sort((a, b) => a - b);
console.log(numbers); // [1, 2, 3, 4]

Reactでの活用例

const fruits = ["Cherry", "Apple", "Banana"];

const SortedFruits = () => {
  const sorted = [...fruits].sort();
  return (
    <ul>
      {sorted.map((fruit, index) => (
        <li key={index}>{fruit}</li>
      ))}
    </ul>
  );
};

6. `splice` メソッド


配列の要素を追加、削除、または置き換えます。

const fruits = ["Apple", "Banana", "Cherry"];
fruits.splice(1, 1, "Orange");
console.log(fruits); // ["Apple", "Orange", "Cherry"]

注意点

  • 不変性の維持spliceは元の配列を直接変更するため、Reactで使用する場合は注意が必要です。sliceやスプレッド構文を活用してコピーを作成し、状態を変更しましょう。
  • 適切なメソッド選択:用途に応じて適切な配列操作メソッドを選ぶことで、コードの可読性と効率が向上します。

まとめ


配列操作の基本メソッドを活用することで、Reactでのデータ操作が効率的になります。次は、配列操作時に注意すべきポイントを学び、実践的なアプローチを深めましょう。

配列を操作する際の注意点

Reactで配列を操作する際には、効率的なコードを書くためのベストプラクティスや潜在的な問題を理解することが重要です。ここでは、配列操作時に注意すべきポイントを解説します。

1. 不変性を保つ


Reactの状態管理では、不変性を維持することが基本です。配列を直接変更せず、新しい配列を作成して状態を更新するようにしましょう。

問題例

const fruits = ["Apple", "Banana"];
fruits.push("Cherry"); // 配列を直接変更
setFruits(fruits); // 状態を正しく更新しない

解決方法

const addFruit = (newFruit) => {
  setFruits([...fruits, newFruit]); // 新しい配列を作成
};

2. `key` 属性の一意性


リストレンダリング時に指定するkey属性は、要素を一意に識別するために必要です。適切なkeyを設定しないと、パフォーマンスが低下したりバグが発生したりすることがあります。

問題例

<ul>
  {fruits.map((fruit) => (
    <li>{fruit}</li> // key がない
  ))}
</ul>

解決方法

<ul>
  {fruits.map((fruit, index) => (
    <li key={index}>{fruit}</li>
  ))}
</ul>

3. パフォーマンスへの配慮


配列が大規模になると、無駄なレンダリングがパフォーマンスの低下につながることがあります。必要に応じてReact.memouseMemoを使ってコンポーネントの再レンダリングを最適化しましょう。

例:不要な再レンダリングを防ぐ

import React, { memo } from "react";

const FruitList = memo(({ fruits }) => {
  return (
    <ul>
      {fruits.map((fruit, index) => (
        <li key={index}>{fruit}</li>
      ))}
    </ul>
  );
});

4. 配列の破壊的メソッドに注意


pushspliceなどの破壊的メソッドは、元の配列を変更します。Reactではこれらを避け、concatやスプレッド構文などを使うことで不変性を保つべきです。

問題例

fruits.splice(1, 1); // 元の配列を変更
setFruits(fruits); // 状態更新の問題を引き起こす

解決方法

const removeFruit = (index) => {
  setFruits(fruits.filter((_, i) => i !== index));
};

5. エラー処理


配列が空の場合や、想定外のデータ構造が渡された場合にエラーが発生する可能性があります。適切な初期値や条件分岐を設定して対処しましょう。

例:条件分岐で安全性を確保

<ul>
  {fruits && fruits.length > 0 ? (
    fruits.map((fruit, index) => <li key={index}>{fruit}</li>)
  ) : (
    <p>No fruits available</p>
  )}
</ul>

6. 配列のコピーに注意


浅いコピーと深いコピーの違いを理解し、オブジェクト配列を操作する際には注意が必要です。

問題例:浅いコピーの影響

const fruits = [{ name: "Apple" }];
const newFruits = [...fruits];
newFruits[0].name = "Banana"; // 元の配列にも影響

解決方法:深いコピー

const deepCopyFruits = JSON.parse(JSON.stringify(fruits));
deepCopyFruits[0].name = "Banana"; // 元の配列は変更されない

まとめ


Reactで配列を操作する際には、不変性を保つことやkey属性の設定、パフォーマンス最適化などに注意が必要です。また、エラーや破壊的メソッドの影響を防ぐ工夫も重要です。次は、これらの配列操作を活用した具体的な応用例について学びましょう。

応用例:TODOリストの実装

配列操作を活用した応用例として、簡単なTODOリストアプリを実装します。この例では、Reactの状態管理と配列操作を組み合わせて、新しいタスクの追加、既存タスクの削除、タスクの完了状態の更新を実現します。

基本構成


まず、useStateフックを使用してタスクの状態を管理します。タスクは、配列として管理され、各タスクは以下のようなオブジェクトとして表現されます:

{ id: 1, text: "Sample Task", completed: false }

TODOリストアプリの完全なコード


以下に、TODOリストの基本機能を実現するReactコンポーネントを示します:

import React, { useState } from "react";

const TodoApp = () => {
  const [tasks, setTasks] = useState([]);
  const [newTask, setNewTask] = useState("");

  // 新しいタスクを追加する関数
  const addTask = () => {
    if (newTask.trim()) {
      setTasks([...tasks, { id: Date.now(), text: newTask, completed: false }]);
      setNewTask("");
    }
  };

  // タスクを削除する関数
  const deleteTask = (id) => {
    setTasks(tasks.filter((task) => task.id !== id));
  };

  // タスクの完了状態を切り替える関数
  const toggleTaskCompletion = (id) => {
    setTasks(
      tasks.map((task) =>
        task.id === id ? { ...task, completed: !task.completed } : task
      )
    );
  };

  return (
    <div>
      <h1>TODOリスト</h1>
      <input
        type="text"
        value={newTask}
        onChange={(e) => setNewTask(e.target.value)}
        placeholder="新しいタスクを入力"
      />
      <button onClick={addTask}>追加</button>

      <ul>
        {tasks.map((task) => (
          <li
            key={task.id}
            style={{
              textDecoration: task.completed ? "line-through" : "none",
            }}
          >
            {task.text}
            <button onClick={() => toggleTaskCompletion(task.id)}>
              {task.completed ? "未完了に戻す" : "完了"}
            </button>
            <button onClick={() => deleteTask(task.id)}>削除</button>
          </li>
        ))}
      </ul>
    </div>
  );
};

export default TodoApp;

コードの詳細解説

  1. タスクの追加
  • addTask関数は、新しいタスクを作成して配列に追加します。タスクにはidとして一意の値を設定しています(Date.now()を使用)。
  • 入力欄の内容はnewTask状態で管理し、追加後にクリアします。
  1. タスクの削除
  • deleteTask関数は、filterメソッドを使って指定したid以外のタスクだけを残した新しい配列を生成します。
  1. タスクの完了状態の切り替え
  • toggleTaskCompletion関数は、mapメソッドを使用して該当するタスクのcompleted状態を反転させています。
  1. スタイリング
  • タスクが完了している場合はtextDecoration: "line-through"で取り消し線を表示します。

機能の拡張例


以下のような機能を追加して、アプリをさらに強化できます:

  1. タスクの編集機能:タスクの内容を直接編集できるようにする。
  2. タスクの優先度設定:タスクに優先度を設定し、並び替えを可能にする。
  3. タスクの保存localStorageやデータベースを利用してタスクを永続化する。

まとめ


このTODOリストの実装を通じて、配列操作をReactで活用する方法を学びました。配列の追加、削除、更新といった基本操作を組み合わせることで、動的で使いやすいアプリケーションを構築できます。次は、配列操作時に発生しやすいエラーやバグの解決方法について学びましょう。

エラーやバグの解決方法

Reactで配列操作を行う際、さまざまなエラーやバグが発生する可能性があります。ここでは、よくある問題とその解決策を具体例を交えて解説します。

1. 状態が正しく更新されない

問題例


配列を直接変更すると、Reactが状態の変更を検知しないため、更新が反映されない場合があります。

const addItem = (item) => {
  items.push(item); // 配列を直接変更
  setItems(items); // Reactは変更を認識しない
};

解決方法


状態を更新する際は、不変性を保つために新しい配列を作成します。

const addItem = (item) => {
  setItems([...items, item]); // 新しい配列を作成
};

2. `key`属性の不備によるレンダリング問題

問題例


リストレンダリングでkeyが設定されていないか、一意でない場合、パフォーマンスの低下や予期しない挙動が発生します。

<ul>
  {items.map((item) => (
    <li>{item.name}</li> // key が指定されていない
  ))}
</ul>

解決方法


配列内の各要素に一意のkeyを設定します。通常は要素のidなどを使用します。

<ul>
  {items.map((item) => (
    <li key={item.id}>{item.name}</li>
  ))}
</ul>

3. 空の配列操作によるエラー

問題例


配列が空の場合、mapfilterが期待どおりに動作しないことがあります。

const renderList = () => {
  return items.map((item) => <li key={item.id}>{item.name}</li>); // itemsが空だとエラー
};

解決方法


条件分岐で空の状態をハンドリングします。

const renderList = () => {
  if (items.length === 0) {
    return <p>No items available</p>;
  }
  return items.map((item) => <li key={item.id}>{item.name}</li>);
};

4. パフォーマンスの低下

問題例


配列が頻繁に更新される場合、大量の再レンダリングが発生してアプリのパフォーマンスが低下します。

解決方法


React.memouseMemoを活用して再レンダリングを最適化します。

import React, { memo } from "react";

const ListItem = memo(({ item }) => <li>{item.name}</li>);

const List = ({ items }) => (
  <ul>
    {items.map((item) => (
      <ListItem key={item.id} item={item} />
    ))}
  </ul>
);

5. 非同期処理での状態更新の競合

問題例


非同期処理で配列の状態を更新する際、競合が発生し、古い状態で更新されることがあります。

const fetchData = async () => {
  const data = await fetchItems();
  setItems([...items, ...data]); // 他の状態変更が上書きされる可能性
};

解決方法


状態更新関数にコールバックを渡して最新の状態を確保します。

const fetchData = async () => {
  const data = await fetchItems();
  setItems((prevItems) => [...prevItems, ...data]);
};

6. 深いコピーと浅いコピーの混乱

問題例


オブジェクト配列を直接操作すると、状態が意図せず変更されることがあります。

const updateItem = (id, newName) => {
  const updatedItems = items;
  updatedItems.find((item) => item.id === id).name = newName; // 元の配列が変更される
  setItems(updatedItems);
};

解決方法


mapメソッドを使って新しい配列を生成します。

const updateItem = (id, newName) => {
  const updatedItems = items.map((item) =>
    item.id === id ? { ...item, name: newName } : item
  );
  setItems(updatedItems);
};

まとめ


配列操作では、不変性の維持、key属性の適切な設定、空の状態や非同期処理の取り扱いに注意が必要です。これらの問題を意識することで、Reactアプリケーションの品質とパフォーマンスを向上させることができます。次は、配列操作の理解を深めるための練習問題に挑戦しましょう。

練習問題で理解を深める

配列操作の理解を深めるために、Reactで配列を扱う際に役立つ練習問題をいくつか用意しました。それぞれの問題に対してヒントも提示するので、ぜひ実践してみてください。


問題 1: リストから重複を削除


以下の配列から重複する要素を取り除いて、ユニークなリストを作成し、表示してください。

const fruits = ["Apple", "Banana", "Apple", "Cherry", "Banana"];

ヒント

  • filterメソッドを活用すると簡単に実現できます。
  • 別解として、Setを利用する方法も試してください。

問題 2: 条件付きリスト表示


以下のオブジェクト配列から、価格が100未満の商品だけを表示するリストを作成してください。

const products = [
  { id: 1, name: "Apple", price: 150 },
  { id: 2, name: "Banana", price: 50 },
  { id: 3, name: "Cherry", price: 80 },
];

ヒント

  • filterメソッドを使い、条件に合致する要素だけを抽出します。

問題 3: 配列のソート


以下の配列をアルファベット順(昇順)と価格の降順で並べ替えてリストを表示してください。

const products = [
  { id: 1, name: "Apple", price: 150 },
  { id: 2, name: "Banana", price: 50 },
  { id: 3, name: "Cherry", price: 80 },
];

ヒント

  • sortメソッドを使用します。
  • 比較関数を使ってカスタムの並べ替えを行ってください。

問題 4: リストのタスク管理


以下のタスクリストをもとに、Reactコンポーネントを作成してください。

  1. タスクを追加する機能
  2. 完了状態を切り替える機能
  3. 完了したタスクをリストの下に並べる機能
const tasks = [
  { id: 1, text: "Do the laundry", completed: false },
  { id: 2, text: "Write an article", completed: true },
  { id: 3, text: "Read a book", completed: false },
];

ヒント

  • タスクの状態管理にはuseStateを利用します。
  • 完了状態を切り替える際にmapメソッドを使用します。
  • 完了状態での並び替えにはfilterを組み合わせると便利です。

問題 5: 合計値の計算


以下のカート内商品リストを使い、商品の合計金額を計算して表示してください。

const cart = [
  { id: 1, name: "Apple", price: 150, quantity: 2 },
  { id: 2, name: "Banana", price: 50, quantity: 5 },
  { id: 3, name: "Cherry", price: 80, quantity: 1 },
];

ヒント

  • reduceメソッドを活用して、price * quantityを足し合わせてください。

問題 6: 動的検索機能


ユーザーが入力した文字列に基づいて、以下の配列から部分一致する要素を表示する検索コンポーネントを作成してください。

const fruits = ["Apple", "Banana", "Cherry", "Avocado"];

ヒント

  • 入力値はuseStateで管理します。
  • 配列の絞り込みにはfilterメソッドを使用します。
  • 大文字と小文字を区別せずに検索できるように、toLowerCase()を活用しましょう。

まとめ


これらの練習問題を通じて、配列操作のスキルを実践的に身につけることができます。回答を試してみて、Reactにおける配列操作の理解をさらに深めましょう。次は記事全体を振り返り、学んだことをまとめます。

まとめ

本記事では、Reactにおける配列操作の基本から応用までを学びました。配列のレンダリング、状態管理、便利なJavaScriptの配列メソッド、配列操作時の注意点を理解することで、Reactでのデータ処理が効率的に行えるようになります。

また、TODOリストのような実践的なアプリケーションを通じて、配列操作の応用例を学び、さらには練習問題を通じて実際の開発で役立つスキルを確認しました。配列操作をしっかりと習得することで、より複雑で洗練されたReactアプリケーションを構築する力が身につきます。

次のステップとして、さらに多機能なプロジェクトを実践しながら、学んだ知識を深めていきましょう。Reactでの開発が楽しく、効率的になることを願っています!

コメント

コメントする

目次