個人開発チームBUILD UP 開発者ブログ

【ToDoアプリを作る】filterを使って配列から特定の要素を削除する。

今回はpropsを渡すおさらいをしながら、登録したタスクの完了時にリストから削除するようにします。

今回も前回の続きからの作業になりますので過去の記事をまだご覧にあってない方は是非参考にしてください。

button.tsxの修正

まずはbutton.tsxを修正します。

前回の記事でtype PropsをonClick: (event: React.MouseEvent<HTMLButtonElement>) => voidと修正したのですが、この書き方だと関数の引数にマウスイベントのある場合しか受け取ることができず、コンポーネント間で受け渡す際にイベントを含まない状態で渡してしまうとエラーとなってしまいます。

そこで、typeの中身の引数をなくして以下のように記述し直しました。

type Props = {
  value: string,
  onClickFunction: () => void
}

また、onClickという名前も、JSX内で実際に使用するonClickを区別するために、onClickFunctionという名前に変更しています。

また、この変更に伴い、const { value, onClickFunction } = props;この部分もonClickから、onClickFunctionに変更になります。

次にreturnの中身を修正します。

変更内容としては、onClick={}のカッコ内を() => {onClickFunction()}}という記述にしております。

    <Button 
      variant="default" 
      color="orange" 
      radius="lg" 
      size="lg" 
      loaderPosition="center" 
      compact 
      uppercase 
      onClick={() => {onClickFunction()}}
    >
      {value}
    </Button>

型エイリアスのtypeの修正でイベントに関する記述を前回の内容に戻して()=>voidにする様に先述しましたが、
<Button>の中身のonClickを上記の通り変更するために型定義を変更しました。

前回までの記述では、onClickに関数をそのまま渡していたのですが、この方法だとeventを有効にすることができるのはコンポーネントのマウント時の一度だけで、実際にボタンをクリックした際にeventを発動させることができないためエラーとなってしまいます。

そこで、関数のeventを発動させるタイミングをずらすためにonClick時に関数を新たに生成するように記述を変更しました。

これにより、エラーの発生を回避することができます。

list.tsxの修正

続いてlist.tsxを修正します。

まずは型定義から修正します。

今回タスクを完了させるための関数を親コンポーネントから受け取ってDemoButtonコンポーネントに渡します。

そこで、関数を受け取るためにPropsに型定義を追加する必要があります。

type Props = {
  taskList: taskType[]
  completeTask: (id: number) => void
}

ここでは、親コンポーネント内でcompleteTaskという関数を定義しますので、その名前の関数を受け取るようにしています。

また、親コンポーネントで定義した関数にはnumber型の「id」という引数を持っているので、カッコ内に定義しておきます。

そして、戻り値がない(returnを含まない)ので、void型(=>void)を定義しています。

次に受けとったpropsを処理します。

  const{taskList, completeTask} = props;

前回までは、taskListだけを受けっていましたが、completeTaskを受け取りますので、波カッコ{}内に追加します。

ここで受けとったcompleteTaskを一度このlist.tsx内で処理します。

list.tsx内で使用しているmapのidを引数に使用してcompleteTaksを実行させるための、handleCompleteという名前の関数を用意しました。

  const handleComplete = (id: number) => {
    completeTask(id);
  };

この関数をDemoButtonコンポーネントに渡して、onClickイベントにて関数が発動するようにします。

では、return内を修正します。

変更内容としては、関数を渡す際のonClickの1行を修正するだけになります。

button.tsx内でも修正しましたがonClickをonClickFunctionに変更しましたので、propsを渡す先の名前も変更mになります。

前回の記事では仮の関数を定義していただけでしたので、今回は仮の関数Aの代わりに()=>handle complete(たsk Item.id)を記述します。

  return (
    <ul>
        {taskList.map((taskItem) => {
            return(
                <li>
                  {taskItem.taskItem}
                  <DemoButton 
                    value={"完了"} 
                    onClickFunction={()=>handleComplete(taskItem.id)}
                  ></DemoButton>
                </li>
            )
        })}
    </ul>

  );

先ほどのonClickの関数と同じく、こちらも中身はおnClickFunction実行時にhandleCompleteが生成されて実行されるように記述しています。

また、taskItem.idを引数とすることで、登録時に割り振られるidと完了用のボタンが紐つけられるので、このidによってリストから削除するための項目を判別することができるようになります。

list.tsxの変更は以上になります。

index.tsxの修正

最後にindex.tsxを修正します。

今回index.tsxでは完了したタスクをリストから削除するための関数を作成してその関数をlist.tsxに渡します。

まずは関数を作成します。

list.tsxでcompleteTaskという名前の関数を受け取るようにしましたので、同じ名前の関数を作成します。

引数にはnumber型のidを指定します。

  const completeTask = (id: number) => {

  };

この関数の中では、newTasksという名前の変数で、taskListの配列から完了したタスクを削除した新たな配列を生成します。

そのnewTaskをsetTaskListを使ってtaskListに再登録することで完了したタスクをリストから除外します。

  const completeTask = (id: number) => {

    setTaskList(newTasks);
  };

まずはsetTaskListを記述しました。

この内容は前回までの記事で紹介したものと同じになります。

それでは肝心のnewTasksの中身を説明します。

この変数ではmapのような配列を処理するメソッドの一つであるfilterを使用します。

filterは配列に含まれる要素に対して、指定した条件と一致する要素だけを抽出して新たに配列を生成します。

先ほどlist.tsxにて配列をmapを使って処理した際のidを使ってリストから完了したタスクを除外すると説明しました。

つまり、除外したいタスクのidだけが判明しているので、そのid以外のタスクを抽出して配列を作り直す必要があります。

では、filterを使って残したいタスクのみを抽出する方法をご説明します。

まず、const newTasks =で変数を定義して、mapを使用するようにして配列名.filterと記述します。

const newTasks = taskList.filter

次にfilter内の引数として(Task)として配列内の要素一つ一つを処理する際の仮の名前をつけます。

そして戻り値のreturnを書きます。

このreturnの中で各配列に割り振られているidと先ほどlist.tsxでDemoButtonに紐付けたidを比較します。

DemoButtonに紐ついているidというのは完了させたい一意のタスクに対するidです。

配列の各要素のidと完了タスクのidがイコールであればそのタスクを除外したいのですが、filterは指定した条件と一致するものだけを抽出するので、指定する条件としてはidが一致しないタスクを全て抽出するように書きます。

この内容をコードで記述すると、以下のようになります。

  const completeTask = (id: number) => {
    const newTasks = taskList.filter((Task) => {
      return Task.id !== id;
    });
    setTaskList(newTasks);
  };

値を比較してイコールではないことを表すために!==と記述します。

これで全タスクと完了タスクの比較が完了し、returnにてidが一致してないタスクだけを配列として取り出すことができました。

こうして取り出された新しい配列のnewTaskをsetTaskListを使って新たに配列に登録し直します。

これが完了タスクを除外する一連の流れになります。

このcompleteTaskをDemoListコンポーネントに渡さなくてはいけません。

続いてreturnの中身を修正します。

まず、少し横道にそれますが、タスクを登録するためのボタンとして使用しているDemoButtonの関数部分を修正しておきます。

button.tsxの型定義にて関数の定義をonClickからonClickFunctionに変更したので、ここでも同様に修正が必要です。

                <DemoButton
                  value={"タスクを登録"} onClickFunction={addTask}
                ></DemoButton>

次にDemoListに関数を渡します。

completeTaskという名前で先ほど作成した関数のcompleteTaskを渡します。

            <DemoList
              taskList={taskList}
              completeTask={completeTask}
            ></DemoList>

作成した関数はDemoListにて処理されて使用されるため、今回は関数を渡すだけで実行はされませんので、直接渡して大丈夫です。

以上で、今回の修正は完了となります。

編集したファイルを全て保存したらlocalhostにアクセスして動作確認をしてみましょう。

適当にタスクを登録した後にリストから完了のボタンを押してみましょう。

タスクがリストから消えれば今回の作業は無事完了となります。

まとめ

  • propsでイベントハンドラを含む関数を渡す際にJSXにて直接渡してしまうとマウントの一度だけしかイベントを有効とすることができないので()=>関数名の形で渡して、関数実行のタイミングでイベントを有効にすることができるようにする。
  • filterを使うと配列から特定の条件に合致した要素だけを抽出することができる。
  • filterで抽出する条件として二つの値を比較して一致していない場合を表すために!==を用いる。

この記事は役に立ちましたか?

もし参考になりましたら、下記のボタンで教えてください。

関連記事

コメント

この記事へのコメントはありません。