

@ 酒井悠宇
Next.jsでサイトを作っているのですが、自分が実装したい機能が配列の要素の入れ替えができれば実現できそうなので、それについて色々調べていきたいと思います。
http://www.htmq.com/js/array_splice.shtml
https://remoter.hatenablog.com/entry/2020/05/07/javascript%E3%81%A7%E9%85%8D%E5%88%97%E3%81%AE%E8%A6%81%E7%B4%A0%E3%82%92%E5%85%A5%E3%82%8C%E6%9B%BF%E3%81%88%E3%82%8B
実際にはそれぞれの枠内には画像が入っていると思ってください。
再現したい挙動としては、「右側のリストになっている画像のいずれかをクリックすると、その画像が左側のメインの枠に入っている画像と置き換わる」みたいな感じです。
例えばこんな感じになっていたとして、
3の画像をクリックすると、
こういう挙動になる感じです。
この機能を実現するためには、[1, 2, 3, 4, 5] とある配列を [3, 2, 1, 4, 5] みたいに並べ替えることができれば実現できそうなので、今回はJavascritpの配列の要素を入れ替えることができる splice() メソッドを使用して実装していきたいと思います。
「入れ替える」と一言に言いましたが、もうちょっと具体的にいうと「削除して追加する」みたいな感じです。
まずは画像のパスを配列にして、それをstateで管理しようと思います。
具体的には以下のようになりました。
const imgPaths: string[] = [
"DSC_4780.jpg",
"DSC06536.jpg",
"DSC_7983-2.jpg",
"DSC_5882.jpg",
"DSC_3955.jpg",
"DSC_2807.jpg",
"DSC_4525.jpg",
];
const [spliceImg, setSpliceImg] = useState<string[]>(imgPaths);
表示するときはstateをmapで回してこんな感じにします。
あとはこれでいい感じにレイアウトを整えれば良さそうです。
説明が長くなるので今回はレイアウトに関しては説明を省きます。
{spliceImg.map((i) => (
<Image src={`/images/${i}`} width={300} height={200}/>
))}
ベースはこれで完成しました。
あとは、画像がクリックされると、クリックされた画像のパスとインデックス番号0の画像のパスが入れ替わるロジックが作られれば完成です。
それではsplice()メソッドについてみていきましょう。
Arrayオブジェクトのsplice()メソッドは、配列空要素を削除・追加して組み替えます。
Arrayオブジェクトのspliceメソッドを実行すると、第一引数で指定した位置から、第二引数で指定した数の要素が配列から削除され、第三引数以降で指定した値が要素として配列に追加されます。
実行した結果には、削除された要素が配列形式で返ります。
配列名.splice()
追加・削除する位置(配列の要素数より大きい値を指定すると配列の末尾となる。負の数値を指定すると配列の末尾から引いた位置となる)
削除する要素の数
追加する要素
削除された要素が配列形式で返される
<script>
//元の配列を用意する
let ary = new Array("いちご", "にんじん", "さんだる")
//配列の1番目から2個の要素を削除して、同じ位置に"ごましお", "ろけっと"を追加
let spliced = ary.splice(1, 2, "ごましお", "ろけっと");
document.write(ary);
</script>
↓ブラウザ上の表示
いちご, ごましお, ろけっとそれではこのsplice()メソッドを使って画像がクリックされた時に配列の要素を入れ替えるロジックを作っていきたいと思います。
こんな感じになりました。
//stateを直接書き換えるとレンダリングされないので展開してから書き換える
const imgList: string[] = [...spliceImg];
//画像クリック時に走る関数
const onClickImg = (i: number): void => {
//クリックされたindexを削除して、そこにindex0の要素を入れる
const deleteImg = imgList.splice(i, 1, imgList[0]);
//spliceの返り値として削除された要素が配列形式で返ってくるので、それをimgListの[0]にぶち込む
imgList[0] = deleteImg[0];
//state書き換え
setSpliceImg(imgList);
};
//jsx内の表示のロジック
{spliceImg.map((i, index) => (
<Image src={`/images/${i}`} width={300} height={200} onClick={() => onClickImg(index)} />
))}
流れは以下のような感じです。
最初はstateを直接書き換えていたのですが、それではレンダリングがはしらずに思い通りの挙動にならなかったので、色々調べてみると以下の記事を見つけました。
React Hooks で配列の要素を削除した後の再描画について
解決策としてはstateを一回スプレッドで展開して変数に代入してから配列操作を行えばいいみたいです。
最後にsetter関数でstateを書き換えるのもお忘れなく。
思い通りの挙動を実現することができました。
これからも実現したい機能の実装方法がわからないときはこんな感じでブログに書いて勉強していきたいと思います
最後までごらんいただきありがとうございました!
なんかNext.jsで画像を色々してたら以下のようなエラーが出たので共有しておきます。
Unhandled Runtime Error ChunkLoadError: Loading chunk nodemodulesnext_dist_client_dev_noop_js failed. (error: http://localhost:3000/_next/static/chunks/fallback/node_modules_next_dist_client_dev_noop_js.js)
https://stackoverflow.com/questions/67652612/chunkloaderror-loading-chunk-node-modules-next-dist-client-dev-noop-js-failed
このサイトに同じエラーが起こっている人を見つけました。
解決法
ルートディレクトリ直下にある「.next」というファイルを削除して「npm run dev 」でサーバー再起動で治りました。