iT邦幫忙

2023 iThome 鐵人賽

DAY 17
0

今天要學習如何在 state 中操作陣列的更新,在 JavaScript 當中陣列是 mutable,但當我們在 React 中處理 array 時應該將它們視為 immutable。所以當我們要更新時,需要創建新的陣列或是複製一個舊的陣列的 copy,再透過 set function 來使用 array。

預備知識

由於在 React 當中 array 應該當作 immutable 來對待,因此在 JavaScript 學習過的方法有些不建議使用:

避免使用(改動到原始的 array) 建議使用 (return 新 array)
追加(adding) push, unshift concat, [...arr] spread syntax
移除(removing) pop, shift, splice filter, slice
替代(replacing) splice, arr[i] = ... assignment map
分類(sorting) reverse, sort copy the array first

*但如果使用 Immer 則二邊都行,Immer 後續有機會再介紹了。

接著來看一些應用例,雖然是不同的應用,但原則基本上都是處理好新的 array,再使用 set function 來觸發渲染。

追加項目

這是一個可追加項目的清單,透過在 input 輸入來新增項目。

import { useState } from "react";

let nextId = 0;

export default function List() {
  const [name, setName] = useState("");
  const [artists, setArtists] = useState([]);

  return (
    <>
      <h1>台灣藝術家</h1>
      <input value={name} onChange={(e) => setName(e.target.value)} />
      <button
        onClick={() => {
          setArtists([...artists, { id: nextId++, name: name }]);
        }}>
        Add
      </button>
      <ul>
        {artists.map((artist) => (
          <li key={artist.id}>{artist.name}</li>
        ))}
      </ul>
    </>
  );
}

<button
  onClick={() => {
    setArtists([...artists, { id: nextId++, name: name }]);
  }}>
  Add
</button>

透過展開的 spread 用法複製了一份舊的藝術家名單,並將新的藝術家資料添加到這份複製的名單中。這樣做可以確保我們不直接修改原始的 artists array,而是創建了一個新的陣列,往新的陣列中添加了新的藝術家資料,這樣可以確保 React 正確地檢測到狀態的變化並進行重新渲染。

移除項目

接著我們想要按按鈕來移除藝術家。

import { useState } from "react";

let initialArtists = [
  { id: 0, name: "黃土水" },
  { id: 1, name: "李石樵" },
  { id: 2, name: "洪瑞麟" },
];

export default function List() {
  const [artists, setArtists] = useState(initialArtists);

  return (
    <>
      <h1>Inspiring sculptors:</h1>
      <ul>
        {artists.map((artist) => (
          <li key={artist.id}>
            {artist.name}{" "}
            <button
              onClick={() => {
                setArtists(artists.filter((a) => a.id !== artist.id));
              }}>
              Delete
            </button>
          </li>
        ))}
      </ul>
    </>
  );
}

讓我們消化一下這邊的邏輯,也就是過濾出不等於當前藝術家(被點擊刪除的那一位)的所有藝術家後再使用 setArtist 來觸發渲染即完成。

移動圓點點


這邊要做的是點擊按鈕後讓圓點點的位置向下位移。

import { useState } from "react";

let initialShapes = [
  { id: 0, type: "circle", x: 50, y: 100 },
  { id: 1, type: "square", x: 150, y: 100 },
  { id: 2, type: "circle", x: 250, y: 100 },
];

export default function ShapeEditor() {
  const [shapes, setShapes] = useState(initialShapes);

  function handleClick() {
    const nextShapes = shapes.map((shape) => {
      if (shape.type === "square") {
        // 不改變
        return shape;
      } else {
        // 回傳新的圓點點,並且下降50px
        return {
          ...shape,
          y: shape.y + 50,
        };
      }
    });
    // 再次渲染
    setShapes(nextShapes);
  }

  return (
    <>
      <button onClick={handleClick}>Move circles down!</button>
      {shapes.map((shape) => (
        <div
          key={shape.id}
          style={{
            background: "purple",
            position: "absolute",
            left: shape.x,
            top: shape.y,
            borderRadius: shape.type === "circle" ? "50%" : "",
            width: 20,
            height: 20,
          }}
        />
      ))}
    </>
  );
}

一樣先來看邏輯,將邏輯編寫在handleClick function 當中,handleClick function 中做二件事,一個是變數用來儲存 nextShapes 的資料,一個是以 setter function 傳入 nextShapes 的資料用來渲染。這邊使用 if else statement 來操作,「若形狀類別為正方形則不變,否則回傳向下位移的新圓點點」,之後再編輯 setter function 這樣就完成了。

以上是今天的學習。今天做了一些陣列的操作,主要的操作方法還是建立在熟悉 JavaScript 的陣列操作上,官方文件也有舉更多的陣列操作例子可以參考看看。

明天要來學習聲明式的思考及操作。

參考資料

  • React 官方文件 Updating Arrays in State

上一篇
Day 16 - 在 state 中更新物件
下一篇
Day 18 - 聲明式 UI 的思考及操作
系列文
30 days of React 30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言