Mảng có thể thay đổi trong JavaScript, nhưng bạn nên coi chúng là bất biến khi bạn lưu trữ chúng ở trạng thái. Cũng giống như với các đối tượng, khi bạn muốn cập nhật một mảng được lưu trữ trong trạng thái, bạn cần tạo một mảng mới [hoặc tạo một bản sao của mảng hiện có], sau đó thiết lập trạng thái để sử dụng mảng mới
Bạn sẽ học
- Cách thêm, xóa hoặc thay đổi các mục trong một mảng ở trạng thái React
- Cách cập nhật một đối tượng bên trong một mảng
- Cách sao chép mảng ít lặp lại hơn với Immer
Cập nhật mảng mà không có đột biến
Trong JavaScript, mảng chỉ là một loại đối tượng khác. Giống như với các đối tượng, bạn nên coi các mảng ở trạng thái React là chỉ đọc. Điều này có nghĩa là bạn không nên gán lại các mục bên trong một mảng như
setArtists[ // Replace the state
[ // with a new array
...artists, // that contains all the old items
{ id: nextId++, name: name } // and one new item at the end
]
];
8 và bạn cũng không nên sử dụng các phương thức làm thay đổi mảng, chẳng hạn như setArtists[ // Replace the state
[ // with a new array
...artists, // that contains all the old items
{ id: nextId++, name: name } // and one new item at the end
]
];
9 và import { useState } from 'react'; let nextId = 0; export default function List[] { const [name, setName] = useState['']; const [artists, setArtists] = useState[[]]; return [ Inspiring sculptors: setName[e.target.value]} /> { setName['']; setArtists[[ ...artists, { id: nextId++, name: name } ]]; }}>Add {artists.map[artist => [ {artist.name} ]]} ]; }0
Thay vào đó, mỗi khi bạn muốn cập nhật một mảng, bạn sẽ muốn chuyển một mảng mới vào hàm cài đặt trạng thái của mình. Để làm điều đó, bạn có thể tạo một mảng mới từ mảng ban đầu ở trạng thái của mình bằng cách gọi các phương thức không thay đổi của nó như
import { useState } from 'react'; let nextId = 0; export default function List[] { const [name, setName] = useState['']; const [artists, setArtists] = useState[[]]; return [ Inspiring sculptors: setName[e.target.value]} /> { setName['']; setArtists[[ ...artists, { id: nextId++, name: name } ]]; }}>Add {artists.map[artist => [ {artist.name} ]]} ]; }1 và
import { useState } from 'react'; let nextId = 0; export default function List[] { const [name, setName] = useState['']; const [artists, setArtists] = useState[[]]; return [ Inspiring sculptors: setName[e.target.value]} /> { setName['']; setArtists[[ ...artists, { id: nextId++, name: name } ]]; }}>Add {artists.map[artist => [ {artist.name} ]]} ]; }2. Sau đó, bạn có thể đặt trạng thái của mình thành mảng mới kết quả
Đây là một bảng tham chiếu của hoạt động mảng phổ biến. Khi xử lý các mảng bên trong trạng thái React, bạn sẽ cần tránh các phương thức ở cột bên trái và thay vào đó hãy ưu tiên các phương thức ở cột bên phải
tránh [biến đổi mảng]thích [trả về một mảng mới]thêm_______2_______3,import { useState } from 'react'; let nextId = 0; export default function List[] { const [name, setName] = useState['']; const [artists, setArtists] = useState[[]]; return [ Inspiring sculptors: setName[e.target.value]} /> { setName['']; setArtists[[ ...artists, { id: nextId++, name: name } ]]; }}>Add {artists.map[artist => [ {artist.name} ]]} ]; }4_______2_______5,
import { useState } from 'react'; let nextId = 0; export default function List[] { const [name, setName] = useState['']; const [artists, setArtists] = useState[[]]; return [ Inspiring sculptors: setName[e.target.value]} /> { setName['']; setArtists[[ ...artists, { id: nextId++, name: name } ]]; }}>Add {artists.map[artist => [ {artist.name} ]]} ]; }6 cú pháp lây lan []loại bỏ
import { useState } from 'react'; let nextId = 0; export default function List[] { const [name, setName] = useState['']; const [artists, setArtists] = useState[[]]; return [ Inspiring sculptors: setName[e.target.value]} /> { setName['']; setArtists[[ ...artists, { id: nextId++, name: name } ]]; }}>Add {artists.map[artist => [ {artist.name} ]]} ]; }7,
import { useState } from 'react'; let nextId = 0; export default function List[] { const [name, setName] = useState['']; const [artists, setArtists] = useState[[]]; return [ Inspiring sculptors: setName[e.target.value]} /> { setName['']; setArtists[[ ...artists, { id: nextId++, name: name } ]]; }}>Add {artists.map[artist => [ {artist.name} ]]} ]; }8,
import { useState } from 'react'; let nextId = 0; export default function List[] { const [name, setName] = useState['']; const [artists, setArtists] = useState[[]]; return [ Inspiring sculptors: setName[e.target.value]} /> { setName['']; setArtists[[ ...artists, { id: nextId++, name: name } ]]; }}>Add {artists.map[artist => [ {artist.name} ]]} ]; }9
setArtists[[
{ id: nextId++, name: name },
...artists // Put old items at the end
]];
0, setArtists[[
{ id: nextId++, name: name },
...artists // Put old items at the end
]];
1 []thay thếimport { useState } from 'react'; let nextId = 0; export default function List[] { const [name, setName] = useState['']; const [artists, setArtists] = useState[[]]; return [ Inspiring sculptors: setName[e.target.value]} /> { setName['']; setArtists[[ ...artists, { id: nextId++, name: name } ]]; }}>Add {artists.map[artist => [ {artist.name} ]]} ]; }9,
setArtists[[
{ id: nextId++, name: name },
...artists // Put old items at the end
]];
3 bài tậpsetArtists[[
{ id: nextId++, name: name },
...artists // Put old items at the end
]];
4 []sắp xếp_______12_______5, setArtists[[
{ id: nextId++, name: name },
...artists // Put old items at the end
]];
6 trước tiên []Ngoài ra, bạn có thể cho phép bạn sử dụng các phương thức từ cả hai cột
cạm bẫy
Thật không may,
setArtists[[
{ id: nextId++, name: name },
...artists // Put old items at the end
]];
1 và import { useState } from 'react'; let nextId = 0; export default function List[] { const [name, setName] = useState['']; const [artists, setArtists] = useState[[]]; return [ Inspiring sculptors: setName[e.target.value]} /> { setName['']; setArtists[[ ...artists, { id: nextId++, name: name } ]]; }}>Add {artists.map[artist => [ {artist.name} ]]} ]; }9 được đặt tên giống nhau nhưng lại rất khác nhau
1 cho phép bạn sao chép một mảng hoặc một phần của nósetArtists[[
{ id: nextId++, name: name },
...artists // Put old items at the end
]];
import { useState } from 'react'; let nextId = 0; export default function List[] { const [name, setName] = useState['']; const [artists, setArtists] = useState[[]]; return [ Inspiring sculptors: setName[e.target.value]} /> { setName['']; setArtists[[ ...artists, { id: nextId++, name: name } ]]; }}>Add {artists.map[artist => [ {artist.name} ]]} ]; }
9 thay đổi mảng [để chèn hoặc xóa các mục]
Trong React, bạn sẽ sử dụng
setArtists[[
{ id: nextId++, name: name },
...artists // Put old items at the end
]];
1 [không có import { useState } from 'react'; let initialArtists = [ { id: 0, name: 'Marta Colvin Andrade' }, { id: 1, name: 'Lamidi Olonade Fakeye'}, { id: 2, name: 'Louise Nevelson'}, ]; export default function List[] { const [artists, setArtists] = useState[ initialArtists ]; return [ Inspiring sculptors: {artists.map[artist => [ {artist.name}{' '} { setArtists[ artists.filter[a => a.id !== artist.id ] ]; }}> Delete ]]} ]; }2. ] thường xuyên hơn vì bạn không muốn thay đổi đối tượng hoặc mảng trong trạng thái. Cập nhật đối tượng giải thích đột biến là gì và tại sao nó không được khuyến nghị cho trạng thái
Thêm vào một mảng
setArtists[ // Replace the state
[ // with a new array
...artists, // that contains all the old items
{ id: nextId++, name: name } // and one new item at the end
]
];
9 sẽ biến đổi một mảng mà bạn không muốnỨng dụng. js
Ứng dụng. jsĐặt lại Ngã ba
import { useState } from 'react'; let nextId = 0; export default function List[] { const [name, setName] = useState['']; const [artists, setArtists] = useState[[]]; return [ Inspiring sculptors: setName[e.target.value]} /> { setName['']; artists.push[{ id: nextId++, name: name, }]; }}>Add {artists.map[artist => [ {artist.name} ]]} ]; }Cho xem nhiều hơn
Thay vào đó, hãy tạo một mảng mới chứa các mục hiện có và một mục mới ở cuối. Có nhiều cách để làm điều này, nhưng cách dễ nhất là sử dụng cú pháp
import { useState } from 'react'; let initialArtists = [ { id: 0, name: 'Marta Colvin Andrade' }, { id: 1, name: 'Lamidi Olonade Fakeye'}, { id: 2, name: 'Louise Nevelson'}, ]; export default function List[] { const [artists, setArtists] = useState[ initialArtists ]; return [ Inspiring sculptors: {artists.map[artist => [ {artist.name}{' '} { setArtists[ artists.filter[a => a.id !== artist.id ] ]; }}> Delete ]]} ]; }4
setArtists[ // Replace the state
[ // with a new array
...artists, // that contains all the old items
{ id: nextId++, name: name } // and one new item at the end
]
];
Bây giờ nó hoạt động chính xác
Ứng dụng. js
Ứng dụng. jsĐặt lại Ngã ba
import { useState } from 'react'; let nextId = 0; export default function List[] { const [name, setName] = useState['']; const [artists, setArtists] = useState[[]]; return [ Inspiring sculptors: setName[e.target.value]} /> { setName['']; setArtists[[ ...artists, { id: nextId++, name: name } ]]; }}>Add {artists.map[artist => [ {artist.name} ]]} ]; }Cho xem nhiều hơn
Cú pháp dàn trải mảng cũng cho phép bạn thêm vào trước một mục bằng cách đặt nó trước bản gốc
import { useState } from 'react'; let initialArtists = [ { id: 0, name: 'Marta Colvin Andrade' }, { id: 1, name: 'Lamidi Olonade Fakeye'}, { id: 2, name: 'Louise Nevelson'}, ]; export default function List[] { const [artists, setArtists] = useState[ initialArtists ]; return [ Inspiring sculptors: {artists.map[artist => [ {artist.name}{' '} { setArtists[ artists.filter[a => a.id !== artist.id ] ]; }}> Delete ]]} ]; }5
setArtists[[
{ id: nextId++, name: name },
...artists // Put old items at the end
]];
Theo cách này, spread có thể thực hiện công việc của cả
setArtists[ // Replace the state
[ // with a new array
...artists, // that contains all the old items
{ id: nextId++, name: name } // and one new item at the end
]
];
9 bằng cách thêm vào cuối mảng và import { useState } from 'react'; let initialArtists = [ { id: 0, name: 'Marta Colvin Andrade' }, { id: 1, name: 'Lamidi Olonade Fakeye'}, { id: 2, name: 'Louise Nevelson'}, ]; export default function List[] { const [artists, setArtists] = useState[ initialArtists ]; return [ Inspiring sculptors: {artists.map[artist => [ {artist.name}{' '} { setArtists[ artists.filter[a => a.id !== artist.id ] ]; }}> Delete ]]} ]; }7 bằng cách thêm vào đầu mảng. Hãy thử nó trong hộp cát ở trên
Loại bỏ khỏi một mảng
Cách dễ nhất để xóa một mục khỏi mảng là lọc nó ra. Nói cách khác, bạn sẽ tạo ra một mảng mới không chứa mục đó. Để làm điều này, hãy sử dụng phương pháp
setArtists[[
{ id: nextId++, name: name },
...artists // Put old items at the end
]];
0, ví dụỨng dụng. js
Ứng dụng. jsĐặt lại Ngã ba
import { useState } from 'react'; let initialArtists = [ { id: 0, name: 'Marta Colvin Andrade' }, { id: 1, name: 'Lamidi Olonade Fakeye'}, { id: 2, name: 'Louise Nevelson'}, ]; export default function List[] { const [artists, setArtists] = useState[ initialArtists ]; return [ Inspiring sculptors: {artists.map[artist => [ {artist.name}{' '} { setArtists[ artists.filter[a => a.id !== artist.id ] ]; }}> Delete ]]} ]; }Cho xem nhiều hơn
Nhấp vào nút "Xóa" một vài lần và xem trình xử lý nhấp chuột của nó
setArtists[
artists.filter[a => a.id !== artist.id]
];
Ở đây,
import { useState } from 'react'; let initialArtists = [ { id: 0, name: 'Marta Colvin Andrade' }, { id: 1, name: 'Lamidi Olonade Fakeye'}, { id: 2, name: 'Louise Nevelson'}, ]; export default function List[] { const [artists, setArtists] = useState[ initialArtists ]; return [ Inspiring sculptors: {artists.map[artist => [ {artist.name}{' '} { setArtists[ artists.filter[a => a.id !== artist.id ] ]; }}> Delete ]]} ]; }9 có nghĩa là “tạo một mảng bao gồm những
setArtists[
artists.filter[a => a.id !== artist.id]
];
0 có ID khác với setArtists[
artists.filter[a => a.id !== artist.id]
];
1”. Nói cách khác, nút “Xóa” của mỗi nghệ sĩ sẽ lọc nghệ sĩ đó ra khỏi mảng, sau đó yêu cầu kết xuất lại với mảng kết quả. Lưu ý rằng setArtists[[
{ id: nextId++, name: name },
...artists // Put old items at the end
]];
0 không sửa đổi mảng ban đầuChuyển đổi một mảng
Nếu bạn muốn thay đổi một số hoặc tất cả các phần tử của mảng, bạn có thể sử dụng
import { useState } from 'react'; let nextId = 0; export default function List[] { const [name, setName] = useState['']; const [artists, setArtists] = useState[[]]; return [ Inspiring sculptors: setName[e.target.value]} /> { setName['']; setArtists[[ ...artists, { id: nextId++, name: name } ]]; }}>Add {artists.map[artist => [ {artist.name} ]]} ]; }2 để tạo một mảng mới. Hàm mà bạn sẽ chuyển đến
setArtists[[
{ id: nextId++, name: name },
...artists // Put old items at the end
]];
4 có thể quyết định phải làm gì với từng mục, dựa trên dữ liệu hoặc chỉ mục của mục đó [hoặc cả hai]Trong ví dụ này, một mảng chứa tọa độ của hai hình tròn và hình vuông. Khi bạn nhấn nút, nó chỉ di chuyển các vòng tròn xuống 50 pixel. Nó thực hiện điều này bằng cách tạo ra một mảng dữ liệu mới bằng cách sử dụng
import { useState } from 'react'; let nextId = 0; export default function List[] { const [name, setName] = useState['']; const [artists, setArtists] = useState[[]]; return [ Inspiring sculptors: setName[e.target.value]} /> { setName['']; setArtists[[ ...artists, { id: nextId++, name: name } ]]; }}>Add {artists.map[artist => [ {artist.name} ]]} ]; }2
Ứng dụng. js
Ứng dụng. jsĐặt lại Ngã ba
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'] { // No change return shape; } else { // Return a new circle 50px below return { ...shape, y: shape.y + 50, }; } }]; // Re-render with the new array setShapes[nextShapes]; } return [ Move circles down! {shapes.map[shape => [ ]]} ]; }Cho xem nhiều hơn
Thay thế các mục trong một mảng
Việc muốn thay thế một hoặc nhiều phần tử trong một mảng là điều đặc biệt phổ biến. Các phép gán như
setArtists[ // Replace the state
[ // with a new array
...artists, // that contains all the old items
{ id: nextId++, name: name } // and one new item at the end
]
];
8 đang thay đổi mảng ban đầu, vì vậy, thay vào đó, bạn cũng sẽ muốn sử dụng setArtists[[
{ id: nextId++, name: name },
...artists // Put old items at the end
]];
4 cho việc nàyĐể thay thế một mục, hãy tạo một mảng mới với
setArtists[[
{ id: nextId++, name: name },
...artists // Put old items at the end
]];
4. Trong cuộc gọi setArtists[[
{ id: nextId++, name: name },
...artists // Put old items at the end
]];
4 của bạn, bạn sẽ nhận được chỉ mục mục làm đối số thứ hai. Sử dụng nó để quyết định trả lại mục ban đầu [đối số đầu tiên] hay cái gì khácỨng dụng. js
Ứng dụng. jsĐặt lại Ngã ba
import { useState } from 'react'; let initialCounters = [ 0, 0, 0 ]; export default function CounterList[] { const [counters, setCounters] = useState[ initialCounters ]; function handleIncrementClick[index] { const nextCounters = counters.map[[c, i] => { if [i === index] { // Increment the clicked counter return c + 1; } else { // The rest haven't changed return c; } }]; setCounters[nextCounters]; } return [ {counters.map[[counter, i] => [ {counter} { handleIncrementClick[i]; }}>+1 ]]} ]; }Cho xem nhiều hơn
Chèn vào một mảng
Đôi khi, bạn có thể muốn chèn một mục vào một vị trí cụ thể không phải ở đầu cũng không phải ở cuối. Để làm điều này, bạn có thể sử dụng cú pháp trải rộng mảng
import { useState } from 'react'; let initialArtists = [ { id: 0, name: 'Marta Colvin Andrade' }, { id: 1, name: 'Lamidi Olonade Fakeye'}, { id: 2, name: 'Louise Nevelson'}, ]; export default function List[] { const [artists, setArtists] = useState[ initialArtists ]; return [ Inspiring sculptors: {artists.map[artist => [ {artist.name}{' '} { setArtists[ artists.filter[a => a.id !== artist.id ] ]; }}> Delete ]]} ]; }4 cùng với phương thức
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'] { // No change return shape; } else { // Return a new circle 50px below return { ...shape, y: shape.y + 50, }; } }]; // Re-render with the new array setShapes[nextShapes]; } return [ Move circles down! {shapes.map[shape => [ ]]} ]; }1. Phương thức
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'] { // No change return shape; } else { // Return a new circle 50px below return { ...shape, y: shape.y + 50, }; } }]; // Re-render with the new array setShapes[nextShapes]; } return [ Move circles down! {shapes.map[shape => [ ]]} ]; }1 cho phép bạn cắt một “lát cắt” của mảng. Để chèn một mục, bạn sẽ tạo một mảng trải rộng lát cắt trước điểm chèn, sau đó là mục mới và sau đó là phần còn lại của mảng ban đầu
Trong ví dụ này, nút Chèn luôn chèn tại chỉ mục
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'] { // No change return shape; } else { // Return a new circle 50px below return { ...shape, y: shape.y + 50, }; } }]; // Re-render with the new array setShapes[nextShapes]; } return [ Move circles down! {shapes.map[shape => [ ]]} ]; }3
Ứng dụng. js
Ứng dụng. jsĐặt lại Ngã ba
import { useState } from 'react'; let nextId = 3; const initialArtists = [ { id: 0, name: 'Marta Colvin Andrade' }, { id: 1, name: 'Lamidi Olonade Fakeye'}, { id: 2, name: 'Louise Nevelson'}, ]; export default function List[] { const [name, setName] = useState['']; const [artists, setArtists] = useState[ initialArtists ]; function handleClick[] { const insertAt = 1; // Could be any index const nextArtists = [ // Items before the insertion point: ...artists.slice[0, insertAt], // New item: { id: nextId++, name: name }, // Items after the insertion point: ...artists.slice[insertAt] ]; setArtists[nextArtists]; setName['']; } return [ Inspiring sculptors: setName[e.target.value]} /> Insert {artists.map[artist => [ {artist.name} ]]} ]; }Cho xem nhiều hơn
Thực hiện các thay đổi khác đối với một mảng
Có một số điều bạn không thể làm với cú pháp trải rộng và các phương pháp không biến đổi như chỉ riêng
import { useState } from 'react'; let nextId = 0; export default function List[] { const [name, setName] = useState['']; const [artists, setArtists] = useState[[]]; return [ Inspiring sculptors: setName[e.target.value]} /> { setName['']; setArtists[[ ...artists, { id: nextId++, name: name } ]]; }}>Add {artists.map[artist => [ {artist.name} ]]} ]; }2 và
import { useState } from 'react'; let nextId = 0; export default function List[] { const [name, setName] = useState['']; const [artists, setArtists] = useState[[]]; return [ Inspiring sculptors: setName[e.target.value]} /> { setName['']; setArtists[[ ...artists, { id: nextId++, name: name } ]]; }}>Add {artists.map[artist => [ {artist.name} ]]} ]; }1. Ví dụ: bạn có thể muốn đảo ngược hoặc sắp xếp một mảng. Các phương thức
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'] { // No change return shape; } else { // Return a new circle 50px below return { ...shape, y: shape.y + 50, }; } }]; // Re-render with the new array setShapes[nextShapes]; } return [ Move circles down! {shapes.map[shape => [ ]]} ]; }6 và
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'] { // No change return shape; } else { // Return a new circle 50px below return { ...shape, y: shape.y + 50, }; } }]; // Re-render with the new array setShapes[nextShapes]; } return [ Move circles down! {shapes.map[shape => [ ]]} ]; }7 của JavaScript đang thay đổi mảng ban đầu, vì vậy bạn không thể sử dụng chúng trực tiếp
Tuy nhiên, bạn có thể sao chép mảng trước rồi thực hiện các thay đổi đối với mảng đó
Ví dụ
Ứng dụng. js
Ứng dụng. jsĐặt lại Ngã ba
import { useState } from 'react'; let nextId = 3; const initialList = [ { id: 0, title: 'Big Bellies' }, { id: 1, title: 'Lunar Landscape' }, { id: 2, title: 'Terracotta Army' }, ]; export default function List[] { const [list, setList] = useState[initialList]; function handleClick[] { const nextList = [...list]; nextList.reverse[]; setList[nextList]; } return [ Reverse {list.map[artwork => [ {artwork.title} ]]} ]; }Cho xem nhiều hơn
Ở đây, bạn sử dụng cú pháp trải rộng
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'] { // No change return shape; } else { // Return a new circle 50px below return { ...shape, y: shape.y + 50, }; } }]; // Re-render with the new array setShapes[nextShapes]; } return [ Move circles down! {shapes.map[shape => [ ]]} ]; }8 để tạo một bản sao của mảng ban đầu trước. Bây giờ bạn đã có một bản sao, bạn có thể sử dụng các phương pháp biến đổi như
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'] { // No change return shape; } else { // Return a new circle 50px below return { ...shape, y: shape.y + 50, }; } }]; // Re-render with the new array setShapes[nextShapes]; } return [ Move circles down! {shapes.map[shape => [ ]]} ]; }9 hoặc
import { useState } from 'react'; let initialCounters = [ 0, 0, 0 ]; export default function CounterList[] { const [counters, setCounters] = useState[ initialCounters ]; function handleIncrementClick[index] { const nextCounters = counters.map[[c, i] => { if [i === index] { // Increment the clicked counter return c + 1; } else { // The rest haven't changed return c; } }]; setCounters[nextCounters]; } return [ {counters.map[[counter, i] => [ {counter} { handleIncrementClick[i]; }}>+1 ]]} ]; }0 hoặc thậm chí chỉ định các mục riêng lẻ với
import { useState } from 'react'; let initialCounters = [ 0, 0, 0 ]; export default function CounterList[] { const [counters, setCounters] = useState[ initialCounters ]; function handleIncrementClick[index] { const nextCounters = counters.map[[c, i] => { if [i === index] { // Increment the clicked counter return c + 1; } else { // The rest haven't changed return c; } }]; setCounters[nextCounters]; } return [ {counters.map[[counter, i] => [ {counter} { handleIncrementClick[i]; }}>+1 ]]} ]; }1
Tuy nhiên, ngay cả khi bạn sao chép một mảng, bạn không thể trực tiếp thay đổi các mục hiện có bên trong mảng đó. Điều này là do quá trình sao chép còn nông—mảng mới sẽ chứa các mục giống như mảng ban đầu. Vì vậy, nếu bạn sửa đổi một đối tượng bên trong mảng đã sao chép, bạn đang thay đổi trạng thái hiện có. Ví dụ, mã như thế này là một vấn đề
setArtists[ // Replace the state
[ // with a new array
...artists, // that contains all the old items
{ id: nextId++, name: name } // and one new item at the end
]
];
0Mặc dù
import { useState } from 'react'; let initialCounters = [ 0, 0, 0 ]; export default function CounterList[] { const [counters, setCounters] = useState[ initialCounters ]; function handleIncrementClick[index] { const nextCounters = counters.map[[c, i] => { if [i === index] { // Increment the clicked counter return c + 1; } else { // The rest haven't changed return c; } }]; setCounters[nextCounters]; } return [ {counters.map[[counter, i] => [ {counter} { handleIncrementClick[i]; }}>+1 ]]} ]; }2 và
import { useState } from 'react'; let initialCounters = [ 0, 0, 0 ]; export default function CounterList[] { const [counters, setCounters] = useState[ initialCounters ]; function handleIncrementClick[index] { const nextCounters = counters.map[[c, i] => { if [i === index] { // Increment the clicked counter return c + 1; } else { // The rest haven't changed return c; } }]; setCounters[nextCounters]; } return [ {counters.map[[counter, i] => [ {counter} { handleIncrementClick[i]; }}>+1 ]]} ]; }3 là hai mảng khác nhau, nhưng
import { useState } from 'react'; let initialCounters = [ 0, 0, 0 ]; export default function CounterList[] { const [counters, setCounters] = useState[ initialCounters ]; function handleIncrementClick[index] { const nextCounters = counters.map[[c, i] => { if [i === index] { // Increment the clicked counter return c + 1; } else { // The rest haven't changed return c; } }]; setCounters[nextCounters]; } return [ {counters.map[[counter, i] => [ {counter} { handleIncrementClick[i]; }}>+1 ]]} ]; }4 và
import { useState } from 'react'; let initialCounters = [ 0, 0, 0 ]; export default function CounterList[] { const [counters, setCounters] = useState[ initialCounters ]; function handleIncrementClick[index] { const nextCounters = counters.map[[c, i] => { if [i === index] { // Increment the clicked counter return c + 1; } else { // The rest haven't changed return c; } }]; setCounters[nextCounters]; } return [ {counters.map[[counter, i] => [ {counter} { handleIncrementClick[i]; }}>+1 ]]} ]; }5 trỏ đến cùng một đối tượng. Vì vậy, bằng cách thay đổi
import { useState } from 'react'; let initialCounters = [ 0, 0, 0 ]; export default function CounterList[] { const [counters, setCounters] = useState[ initialCounters ]; function handleIncrementClick[index] { const nextCounters = counters.map[[c, i] => { if [i === index] { // Increment the clicked counter return c + 1; } else { // The rest haven't changed return c; } }]; setCounters[nextCounters]; } return [ {counters.map[[counter, i] => [ {counter} { handleIncrementClick[i]; }}>+1 ]]} ]; }6, bạn cũng đang thay đổi
import { useState } from 'react'; let initialCounters = [ 0, 0, 0 ]; export default function CounterList[] { const [counters, setCounters] = useState[ initialCounters ]; function handleIncrementClick[index] { const nextCounters = counters.map[[c, i] => { if [i === index] { // Increment the clicked counter return c + 1; } else { // The rest haven't changed return c; } }]; setCounters[nextCounters]; } return [ {counters.map[[counter, i] => [ {counter} { handleIncrementClick[i]; }}>+1 ]]} ]; }7. Đây là một đột biến trạng thái, mà bạn nên tránh. Bạn có thể giải quyết vấn đề này theo cách tương tự —bằng cách sao chép các mục riêng lẻ mà bạn muốn thay đổi thay vì thay đổi chúng. Đây là cách
Cập nhật các đối tượng bên trong mảng
Các đối tượng không thực sự nằm trong các mảng bên trong. Chúng có thể xuất hiện "bên trong" trong mã, nhưng mỗi đối tượng trong một mảng là một giá trị riêng biệt, mà mảng "chỉ" tới. Đây là lý do tại sao bạn cần cẩn thận khi thay đổi các trường lồng nhau như
import { useState } from 'react'; let initialCounters = [ 0, 0, 0 ]; export default function CounterList[] { const [counters, setCounters] = useState[ initialCounters ]; function handleIncrementClick[index] { const nextCounters = counters.map[[c, i] => { if [i === index] { // Increment the clicked counter return c + 1; } else { // The rest haven't changed return c; } }]; setCounters[nextCounters]; } return [ {counters.map[[counter, i] => [ {counter} { handleIncrementClick[i]; }}>+1 ]]} ]; }5. Danh sách tác phẩm nghệ thuật của người khác có thể trỏ đến cùng một phần tử của mảng
Khi cập nhật trạng thái lồng nhau, bạn cần tạo các bản sao từ điểm bạn muốn cập nhật và cho đến cấp cao nhất. Hãy xem cách nó hoạt động
Trong ví dụ này, hai danh sách tác phẩm nghệ thuật riêng biệt có cùng trạng thái ban đầu. Chúng được cho là bị cô lập, nhưng do đột biến, trạng thái của chúng vô tình bị chia sẻ và việc chọn một hộp trong một danh sách sẽ ảnh hưởng đến danh sách kia
Ứng dụng. js
Ứng dụng. jsĐặt lại Ngã ba
setArtists[ // Replace the state
[ // with a new array
...artists, // that contains all the old items
{ id: nextId++, name: name } // and one new item at the end
]
];
1Cho xem nhiều hơnVấn đề là trong mã như thế này
setArtists[ // Replace the state
[ // with a new array
...artists, // that contains all the old items
{ id: nextId++, name: name } // and one new item at the end
]
];
2Mặc dù bản thân mảng
import { useState } from 'react'; let initialCounters = [ 0, 0, 0 ]; export default function CounterList[] { const [counters, setCounters] = useState[ initialCounters ]; function handleIncrementClick[index] { const nextCounters = counters.map[[c, i] => { if [i === index] { // Increment the clicked counter return c + 1; } else { // The rest haven't changed return c; } }]; setCounters[nextCounters]; } return [ {counters.map[[counter, i] => [ {counter} { handleIncrementClick[i]; }}>+1 ]]} ]; }9 là mới, nhưng bản thân các phần tử vẫn giống như trong mảng
import { useState } from 'react'; let nextId = 3; const initialArtists = [ { id: 0, name: 'Marta Colvin Andrade' }, { id: 1, name: 'Lamidi Olonade Fakeye'}, { id: 2, name: 'Louise Nevelson'}, ]; export default function List[] { const [name, setName] = useState['']; const [artists, setArtists] = useState[ initialArtists ]; function handleClick[] { const insertAt = 1; // Could be any index const nextArtists = [ // Items before the insertion point: ...artists.slice[0, insertAt], // New item: { id: nextId++, name: name }, // Items after the insertion point: ...artists.slice[insertAt] ]; setArtists[nextArtists]; setName['']; } return [ Inspiring sculptors: setName[e.target.value]} /> Insert {artists.map[artist => [ {artist.name} ]]} ]; }0 ban đầu. Vì vậy, việc thay đổi
import { useState } from 'react'; let nextId = 3; const initialArtists = [ { id: 0, name: 'Marta Colvin Andrade' }, { id: 1, name: 'Lamidi Olonade Fakeye'}, { id: 2, name: 'Louise Nevelson'}, ]; export default function List[] { const [name, setName] = useState['']; const [artists, setArtists] = useState[ initialArtists ]; function handleClick[] { const insertAt = 1; // Could be any index const nextArtists = [ // Items before the insertion point: ...artists.slice[0, insertAt], // New item: { id: nextId++, name: name }, // Items after the insertion point: ...artists.slice[insertAt] ]; setArtists[nextArtists]; setName['']; } return [ Inspiring sculptors: setName[e.target.value]} /> Insert {artists.map[artist => [ {artist.name} ]]} ]; }1 sẽ thay đổi mục tác phẩm nghệ thuật gốc. Tác phẩm nghệ thuật đó cũng nằm trong
import { useState } from 'react'; let nextId = 3; const initialArtists = [ { id: 0, name: 'Marta Colvin Andrade' }, { id: 1, name: 'Lamidi Olonade Fakeye'}, { id: 2, name: 'Louise Nevelson'}, ]; export default function List[] { const [name, setName] = useState['']; const [artists, setArtists] = useState[ initialArtists ]; function handleClick[] { const insertAt = 1; // Could be any index const nextArtists = [ // Items before the insertion point: ...artists.slice[0, insertAt], // New item: { id: nextId++, name: name }, // Items after the insertion point: ...artists.slice[insertAt] ]; setArtists[nextArtists]; setName['']; } return [ Inspiring sculptors: setName[e.target.value]} /> Insert {artists.map[artist => [ {artist.name} ]]} ]; }2, gây ra lỗi. Những lỗi như thế này có thể khó nghĩ đến, nhưng may mắn là chúng sẽ biến mất nếu bạn tránh trạng thái đột biến
Bạn có thể sử dụng
setArtists[[
{ id: nextId++, name: name },
...artists // Put old items at the end
]];
4 để thay thế một mục cũ bằng phiên bản cập nhật của nó mà không bị thay đổisetArtists[ // Replace the state
[ // with a new array
...artists, // that contains all the old items
{ id: nextId++, name: name } // and one new item at the end
]
];
3Ở đây,
import { useState } from 'react'; let initialArtists = [ { id: 0, name: 'Marta Colvin Andrade' }, { id: 1, name: 'Lamidi Olonade Fakeye'}, { id: 2, name: 'Louise Nevelson'}, ]; export default function List[] { const [artists, setArtists] = useState[ initialArtists ]; return [ Inspiring sculptors: {artists.map[artist => [ {artist.name}{' '} { setArtists[ artists.filter[a => a.id !== artist.id ] ]; }}> Delete ]]} ]; }4 là cú pháp lây lan đối tượng được sử dụng để
Với phương pháp này, không có mục trạng thái hiện có nào bị thay đổi và lỗi đã được sửa
Ứng dụng. js
Ứng dụng. jsĐặt lại Ngã ba
setArtists[ // Replace the state
[ // with a new array
...artists, // that contains all the old items
{ id: nextId++, name: name } // and one new item at the end
]
];
4Cho xem nhiều hơnNói chung, bạn chỉ nên thay đổi các đối tượng mà bạn vừa tạo. Nếu bạn đang chèn một tác phẩm nghệ thuật mới, bạn có thể thay đổi nó, nhưng nếu bạn đang xử lý thứ gì đó đã có sẵn, bạn cần tạo một bản sao
Viết logic cập nhật ngắn gọn với Immer
Cập nhật các mảng lồng nhau mà không có đột biến có thể hơi lặp lại.
- Nói chung, bạn không cần cập nhật trạng thái nhiều hơn một vài cấp độ. Nếu các đối tượng trạng thái của bạn rất sâu, bạn có thể muốn sao cho chúng bằng phẳng
- Nếu bạn không muốn thay đổi cấu trúc trạng thái của mình, bạn có thể thích sử dụng Immer hơn, cho phép bạn viết bằng cú pháp thuận tiện nhưng có thể thay đổi và đảm nhiệm việc tạo các bản sao cho bạn
Đây là ví dụ về Art Bucket List được viết lại bằng Immer
Ứng dụng. gói js. json
Ứng dụng. jsĐặt lại Ngã ba
setArtists[ // Replace the state
[ // with a new array
...artists, // that contains all the old items
{ id: nextId++, name: name } // and one new item at the end
]
];
5Cho xem nhiều hơnLưu ý cách với Immer, đột biến như
import { useState } from 'react'; let nextId = 3; const initialArtists = [ { id: 0, name: 'Marta Colvin Andrade' }, { id: 1, name: 'Lamidi Olonade Fakeye'}, { id: 2, name: 'Louise Nevelson'}, ]; export default function List[] { const [name, setName] = useState['']; const [artists, setArtists] = useState[ initialArtists ]; function handleClick[] { const insertAt = 1; // Could be any index const nextArtists = [ // Items before the insertion point: ...artists.slice[0, insertAt], // New item: { id: nextId++, name: name }, // Items after the insertion point: ...artists.slice[insertAt] ]; setArtists[nextArtists]; setName['']; } return [ Inspiring sculptors: setName[e.target.value]} /> Insert {artists.map[artist => [ {artist.name} ]]} ]; }5 hiện không sao
setArtists[ // Replace the state
[ // with a new array
...artists, // that contains all the old items
{ id: nextId++, name: name } // and one new item at the end
]
];
6Điều này là do bạn không thay đổi trạng thái ban đầu, nhưng bạn đang thay đổi một đối tượng
import { useState } from 'react'; let nextId = 3; const initialArtists = [ { id: 0, name: 'Marta Colvin Andrade' }, { id: 1, name: 'Lamidi Olonade Fakeye'}, { id: 2, name: 'Louise Nevelson'}, ]; export default function List[] { const [name, setName] = useState['']; const [artists, setArtists] = useState[ initialArtists ]; function handleClick[] { const insertAt = 1; // Could be any index const nextArtists = [ // Items before the insertion point: ...artists.slice[0, insertAt], // New item: { id: nextId++, name: name }, // Items after the insertion point: ...artists.slice[insertAt] ]; setArtists[nextArtists]; setName['']; } return [ Inspiring sculptors: setName[e.target.value]} /> Insert {artists.map[artist => [ {artist.name} ]]} ]; }6 đặc biệt do Immer cung cấp. Tương tự, bạn có thể áp dụng các phương pháp biến đổi như
setArtists[ // Replace the state
[ // with a new array
...artists, // that contains all the old items
{ id: nextId++, name: name } // and one new item at the end
]
];
9 và import { useState } from 'react'; let nextId = 0; export default function List[] { const [name, setName] = useState['']; const [artists, setArtists] = useState[[]]; return [ Inspiring sculptors: setName[e.target.value]} /> { setName['']; setArtists[[ ...artists, { id: nextId++, name: name } ]]; }}>Add {artists.map[artist => [ {artist.name} ]]} ]; }0 cho nội dung của
import { useState } from 'react'; let nextId = 3; const initialArtists = [ { id: 0, name: 'Marta Colvin Andrade' }, { id: 1, name: 'Lamidi Olonade Fakeye'}, { id: 2, name: 'Louise Nevelson'}, ]; export default function List[] { const [name, setName] = useState['']; const [artists, setArtists] = useState[ initialArtists ]; function handleClick[] { const insertAt = 1; // Could be any index const nextArtists = [ // Items before the insertion point: ...artists.slice[0, insertAt], // New item: { id: nextId++, name: name }, // Items after the insertion point: ...artists.slice[insertAt] ]; setArtists[nextArtists]; setName['']; } return [ Inspiring sculptors: setName[e.target.value]} /> Insert {artists.map[artist => [ {artist.name} ]]} ]; }6
Đằng sau hậu trường, Immer luôn xây dựng trạng thái tiếp theo từ đầu theo những thay đổi mà bạn đã thực hiện đối với
import { useState } from 'react'; let nextId = 3; const initialArtists = [ { id: 0, name: 'Marta Colvin Andrade' }, { id: 1, name: 'Lamidi Olonade Fakeye'}, { id: 2, name: 'Louise Nevelson'}, ]; export default function List[] { const [name, setName] = useState['']; const [artists, setArtists] = useState[ initialArtists ]; function handleClick[] { const insertAt = 1; // Could be any index const nextArtists = [ // Items before the insertion point: ...artists.slice[0, insertAt], // New item: { id: nextId++, name: name }, // Items after the insertion point: ...artists.slice[insertAt] ]; setArtists[nextArtists]; setName['']; } return [ Inspiring sculptors: setName[e.target.value]} /> Insert {artists.map[artist => [ {artist.name} ]]} ]; }6. Điều này giữ cho trình xử lý sự kiện của bạn rất ngắn gọn mà không bao giờ thay đổi trạng thái
Tóm tắt lại
- Bạn có thể đặt mảng vào trạng thái, nhưng bạn không thể thay đổi chúng
- Thay vì thay đổi một mảng, hãy tạo một phiên bản mới của nó và cập nhật trạng thái cho nó
- Bạn có thể sử dụng cú pháp trải rộng mảng
import { useState } from 'react'; let nextId = 3; const initialList = [ { id: 0, title: 'Big Bellies' }, { id: 1, title: 'Lunar Landscape' }, { id: 2, title: 'Terracotta Army' }, ]; export default function List[] { const [list, setList] = useState[initialList]; function handleClick[] { const nextList = [...list]; nextList.reverse[]; setList[nextList]; } return [ Reverse {list.map[artwork => [ {artwork.title} ]]} ]; }
1 để tạo mảng với các mục mới - Bạn có thể sử dụng
import { useState } from 'react'; let nextId = 0; export default function List[] { const [name, setName] = useState['']; const [artists, setArtists] = useState[[]]; return [ Inspiring sculptors: setName[e.target.value]} /> { setName['']; setArtists[[ ...artists, { id: nextId++, name: name } ]]; }}>Add {artists.map[artist => [ {artist.name} ]]} ]; }
1 vàimport { useState } from 'react'; let nextId = 0; export default function List[] { const [name, setName] = useState['']; const [artists, setArtists] = useState[[]]; return [ Inspiring sculptors: setName[e.target.value]} /> { setName['']; setArtists[[ ...artists, { id: nextId++, name: name } ]]; }}>Add {artists.map[artist => [ {artist.name} ]]} ]; }
2 để tạo mảng mới với các mục được lọc hoặc biến đổi - Bạn có thể sử dụng Immer để giữ cho mã của bạn ngắn gọn
Hãy thử một số thử thách
1. Cập nhật một mặt hàng trong giỏ hàng2. Xóa một mặt hàng khỏi giỏ hàng3. Sửa các đột biến bằng các phương pháp không đột biến4. Sửa các đột biến bằng cách sử dụng Immer