useState 陣列與物件基礎語法
- 複製狀態:使用 展開運算子 (Spread Operator)
... 將既有物件或陣列內容提取出來。 - 物件更新:以
{ ...prevObj, key: newValue } 的寫法覆寫特定屬性,同時保留其餘未修改的資料。 - 陣列新增:將新元素與展開的舊陣列放入新陣列中,如
[...prevArray, newItem]。 - 陣列刪除:使用
filter() 方法篩選出要保留的元素,藉此產生不含目標元素的新陣列。 - 陣列修改:使用
map() 方法尋找特定元素並替換成新值,其餘元素保持不變。
常見錯誤與解決方法
- 直接修改狀態:使用了
push() 或 obj.key = value 導致畫面未更新,建議使用狀態更新函式搭配展開運算子產生新參照 - 遺漏既有資料:更新物件時忘記展開舊狀態導致其他屬性消失,建議先寫
...prevState 再寫要更新的屬性欄位
import { useState } from 'react';
export default function ProfileManager() {
const [user, setUser] = useState({ name: '張三', age: 25 })
const [tasks, setTasks] = useState([
{ id: crypto.randomUUID(), text: '寫程式', completed: false },
{ id: crypto.randomUUID(), text: '看書', completed: false }
]);
const updateName = () => {
setUser(prevUser => ({ ...prevUser, name: '李四' }));
};
const addTask = () => {
setTasks(prevTasks => {
const newTask = { id: crypto.randomUUID(), text: '運動', completed: false };
return [...prevTasks, newTask];
});
};
const removeTask = (targetId) => {
setTasks(prevTasks => prevTasks.filter(task => task.id !== targetId));
};
const toggleTask = (targetId) => {
setTasks(prevTasks => prevTasks.map(task =>
task.id === targetId
? { ...task, completed: !task.completed }
: task
));
};
return (
<div>
<h2>使用者:{user.name},年齡:{user.age}</h2>
<button onClick={updateName}>改名為李四</button>
<h3>任務列表:</h3>
<ul>
{tasks.map((task) => (
<li key={task.id} style={{ textDecoration: task.completed ? 'line-through' : 'none' }}>
{task.text}
<button onClick={() => toggleTask(task.id)}>
{task.completed ? '標為未完成' : '標為完成'}
</button>
<button onClick={() => removeTask(task.id)}>刪除</button>
</li>
))}
</ul>
<button onClick={addTask}>新增運動任務</button>
</div>
);
}