我們已經理解了 React 的「不可變性」與「閉包」。今天我們要來看兩個在 React 中出現率高達 90% 的 ES6 語法:解構賦值 (Destructuring) 與 展開運算子 (Spread Operator)。
這兩個語法不僅能讓程式碼變乾淨,更是操作 Immutable State(「資料不可變狀態) 的標準配備。
解構賦值能讓我們直接將物件或陣列中的資料提取成獨立變數。
為什麼 useState 是寫成 const [count, setCount] = useState(0)?
因為 useState() 回傳的是一個包含兩個元素的陣列:[當前狀態, 更新函數]。
// 傳統寫法
const stateArray = useState(0);
const count = stateArray[0];
const setCount = stateArray[1];
// 陣列解構
const [count, setCount] = useState(0);
在接收組件 Props 時,解構賦值能省去大量重複的 props. 前綴,還能直接設定預設值 (Default Values) 與 重新命名 (Aliasing):
// 在參數列直接解構 Props 並賦予預設值
function UserCard({ name, role = 'Guest', age: userAge }) {
return (
<div>
<h3>{name} ({role})</h3>
<p>Age: {userAge}</p>
</div>
);
}
展開運算子(...)用來將物件或陣列的內容「展開」出來,這是實現 Immutability (不可變更新) 最常採用的語法。
更新物件 State 時,我們使用 ... 複製原屬性,並在後面寫上要更新的屬性進行覆蓋:
const [user, setUser] = useState({ name: 'Alice', age: 20, city: 'Taipei' });
// 複製舊物件並覆蓋 age
const handleBirthday = () => {
setUser({
...user, // 展開 name, age, city
age: 21 // 覆蓋 age,回傳新物件參考
});
};
要注意:後面的屬性會覆蓋前面的屬性!若順序寫反(例如 { age: 21, ...user }),結果會變成age先存 21 然後被 20 覆蓋掉
在 React 中更新陣列 State 時,絕不能使用會修改原陣列的 push 或 unshift,應改用展開運算子建立新陣列:
const [items, setItems] = useState(['A', 'B']);
// 錯誤:push 會 直接修改原陣列
items.push('C');
// 正確:新增元素到末端
setItems([...items, 'C']); // ['A', 'B', 'C']
// 正確:新增元素到最前端
setItems(['Header', ...items]); // ['Header', 'A', 'B']
雖然同樣是 ...,但當它出現在賦值或參數列表時,稱為「其餘運算子」,用來收集剩餘的資料。
實務應用:過濾特定屬性或透傳 Props
// 1. 從物件中剔除 password,保留其餘資料
const user = { id: 1, name: 'Alice', password: '123' };
const { password, ...safeUser } = user;
console.log(safeUser); // 結果會是{ id: 1, name: 'Alice' }
// 2. 組件 Props 透傳 (Rest Props Pass-through)
function CustomButton({ label, ...restProps }) {
return (
// restProps 包含了 onClick, disabled, className 等剩餘屬性
<button className="btn" {...restProps}>
{label}
</button>
);
}