🧚

配列操作するカスタムフック作ってみた

2021/11/10に公開
2

はじめに

今回配列操作毎回書くのめんどくさいなと思い、かつstateとして配列を扱いたかっため実装してみました。
学習用メモになります。

環境

"typescript": "^4.1.3",
"react": "^17.0.1",
"lodash": "^4.17.21"

実装結果

配列のディープコピー

深いネストを考慮してlodashを採用

import _ from 'lodash'
type deepCopyType = { <T>(array: T[]): T[] }

export const deepCopy: deepCopyType = <T>(array: T[]) => {
  const newArray = _.cloneDeep(array)
  return newArray
}

配列操作

import { useState } from "react";
import { deepCopy } from "../../../../utils/deepCopy";

export const useArrayOperation = <T>( data: T[]) => {
  const [array, setArray] = useState(data)

  // 要素追加
  const addArray = (data: T) => {
    setArray([...array, data]);
  }
  // 要素削除
  const removeArray = (index: number) => {
    const result = deepCopy(array);
    result.splice(index, 1);
    setArray(result)
  }
  // 要素更新
  const updateArray = (index: number, data: T) => {
    const result = deepCopy(array);
    result.splice(index, 1, data);
    setArray(result)
  }

  return [
   array, 
   setArray, 
   { addArray, removeArray, updateArray }
  ] as const
}

1.実装内容 配列をディープコピーする関数を作成

いきなり配列操作に入る前に、配列操作を行う際に、ディープコピーしておかないと変更元の配列オブジェクトにも影響がでてしまうため、ディープコピーをするための関数を用意します。

カスタムフック関数側で、実装することもできますが今回は別のファイルでも使用したい場合を想定して、ファイルを分けます。

今回はlodashを採用しました。

lodash install

$ npm i --save lodash
$ npm i --save-dev @types/lodash

lodashでcloneDeep

installができたら実装です。
lodashにあるcloneDeep関数を使用するとディープコピーを行うことができます
参考: https://lodash.com/docs/4.17.15#cloneDeep

import _ from 'lodash'
export const deepCopy = <T>(array: T[]): T[] => {
  const deepCopyArray = _.cloneDeep(array)
  return deepCopyArray
}

実装内容.2 カスタムフック用意

ディープコピー用の関数を作成したので
あとは

  • 配列のstate作成
  • 配列操作(追加、更新、削除)
    を含めたカスタムフック関数を用意します。

配列のstate作成

useStateでパラメータで受け取った配列のオブジェクトをstateに登録します。
関数でdataに対しての型をT(ジェネリクス)と定義することで、色々な配列の型を関数内の処理で適応できます。

import { useState } from "react";

export const useArrayOperation = <T>( data: T[]) => {
  // type 
  // array: T[]
  const [array, setArray] = useState(data)
}

配列操作(追加、更新、削除)

useStateで生成した配列を操作する関数を用意します

import { useState } from "react";

export const useArrayOperation = <T>( data: T[]) => {
  // type 
  // array: T[]
  const [array, setArray] = useState(data)
}

// 要素追加
const addArray = (data: T) => {
}
// 要素削除
const removeArray = (index: number) => {
}
// 要素更新
const updateArray = (index: number, data: T) => {
}

要素追加

追加に関しては、既存の配列の中のオブジェクトに対して何か行うわけではないのでsetStateで追加します。

import { useState } from "react";

export const useArrayOperation = <T>( data: T[]) => {
  // type 
  // array: T[]
  const [array, setArray] = useState(data)
}

// 要素追加
const arrayAdd = (data: T) => {
 setArray([...array, data]);
}
// 〜〜 省略 〜〜

要素削除、更新

削除、更新を行う際に参照元まで反映してしまうパターンがある
反映してほしくない時が存在したので今回deepCopy関数を用意しspliceで配列操作を行っています。


import { useState } from "react";
import { deepCopy } from "../../../../utils/deepCopy";

export const useArrayOperation = <T>( data: T[]) => {
  // type 
  // array: T[]
  const [array, setArray] = useState(data)
}

// 要素追加
const addArray = (data: T) => {
  setArray([...array, data]);
}
// 要素削除
const removeArray = (index: number) => {
    const result = deepCopy(array);
    result.splice(index, 1);
    setArray(result)
}
// 要素更新
const updateArray = (index: number, data: T) => {
    const result = deepCopy(array);
    result.splice(index, 1, data);
    setArray(result)
}

おわり

以上が、配列操作できるカスタムフックでした。

参考

Array.prototype.splice()

JavaScriptでディープコピーしたい時

Discussion

てべすてんてべすてん

このhooksをreactにデフォで組み込んでおいてほしい、、、

yutoyuto

ありがとうございます
控えにいってめちゃ嬉しいです。