Làm cách nào để cập nhật giá trị đối tượng lồng nhau trong JavaScript?

Các bài viết được liệt kê trong đưa ra một số ví dụ hay về cách thực hiện các thao tác cập nhật cơ bản không thay đổi, chẳng hạn như cập nhật một trường trong một đối tượng hoặc thêm một mục vào cuối một mảng. Tuy nhiên, bộ giảm tốc thường sẽ cần sử dụng kết hợp các thao tác cơ bản đó để thực hiện các tác vụ phức tạp hơn. Dưới đây là một số ví dụ cho một số nhiệm vụ phổ biến hơn mà bạn có thể phải triển khai

Cập nhật các đối tượng lồng nhau

Chìa khóa để cập nhật dữ liệu lồng nhau là mọi cấp độ lồng nhau phải được sao chép và cập nhật một cách thích hợp. Đây thường là một khái niệm khó đối với những người học Redux và có một số vấn đề cụ thể thường xảy ra khi cố gắng cập nhật các đối tượng lồng nhau. Những điều này dẫn đến đột biến trực tiếp ngẫu nhiên và nên tránh

Cách tiếp cận đúng. Sao chép tất cả các cấp dữ liệu lồng nhau

Thật không may, quá trình áp dụng chính xác các bản cập nhật bất biến cho trạng thái được lồng sâu có thể dễ dàng trở nên dài dòng và khó đọc. Đây là ví dụ về việc cập nhật

function updateNestedState(state, action) {
let nestedState = state.nestedState
// ERROR: this directly modifies the existing object reference - don't do this!
nestedState.nestedField = action.data

return {
...state,
nestedState
}
}
1 có thể trông như thế nào

function updateVeryNestedField(state, action) {
return {
...state,
first: {
...state.first,
second: {
...state.first.second,
[action.someId]: {
...state.first.second[action.someId],
fourth: action.someValue
}
}
}
}
}

Rõ ràng, mỗi lớp lồng làm cho điều này khó đọc hơn và có nhiều cơ hội mắc lỗi hơn. Đây là một trong nhiều lý do tại sao bạn được khuyến khích giữ cho trạng thái của mình phẳng và soạn các bộ giảm tốc càng nhiều càng tốt

Sai lầm phổ biến #1. Các biến mới trỏ đến cùng một đối tượng

Xác định một biến mới không tạo ra một đối tượng thực tế mới - nó chỉ tạo ra một tham chiếu khác cho cùng một đối tượng. Một ví dụ về lỗi này sẽ là

function updateNestedState(state, action) {
let nestedState = state.nestedState
// ERROR: this directly modifies the existing object reference - don't do this!
nestedState.nestedField = action.data

return {
...state,
nestedState
}
}

Hàm này trả về chính xác một bản sao nông của đối tượng trạng thái cấp cao nhất, nhưng vì biến

function updateNestedState(state, action) {
let nestedState = state.nestedState
// ERROR: this directly modifies the existing object reference - don't do this!
nestedState.nestedField = action.data

return {
...state,
nestedState
}
}
2 vẫn trỏ vào đối tượng hiện có nên trạng thái đã bị thay đổi trực tiếp

Sai lầm thường gặp #2. Chỉ tạo một bản sao nông của một cấp

Một phiên bản phổ biến khác của lỗi này trông như thế này

function updateNestedState(state, action) {
// Problem: this only does a shallow copy!
let newState = { ...state }

// ERROR: nestedState is still the same object!
newState.nestedState.nestedField = action.data

return newState
}

Sao chép nông ở cấp cao nhất là không đủ - đối tượng

function updateNestedState(state, action) {
let nestedState = state.nestedState
// ERROR: this directly modifies the existing object reference - don't do this!
nestedState.nestedField = action.data

return {
...state,
nestedState
}
}
2 cũng nên được sao chép

Chèn và xóa các mục trong mảng

Thông thường, nội dung của mảng Javascript được sửa đổi bằng cách sử dụng các hàm thay đổi như

function updateNestedState(state, action) {
let nestedState = state.nestedState
// ERROR: this directly modifies the existing object reference - don't do this!
nestedState.nestedField = action.data

return {
...state,
nestedState
}
}
4,
function updateNestedState(state, action) {
let nestedState = state.nestedState
// ERROR: this directly modifies the existing object reference - don't do this!
nestedState.nestedField = action.data

return {
...state,
nestedState
}
}
5 và
function updateNestedState(state, action) {
let nestedState = state.nestedState
// ERROR: this directly modifies the existing object reference - don't do this!
nestedState.nestedField = action.data

return {
...state,
nestedState
}
}
6. Vì chúng tôi không muốn thay đổi trạng thái trực tiếp trong bộ giảm tốc, nên thường nên tránh những trạng thái đó. Do đó, bạn có thể thấy hành vi "chèn" hoặc "xóa" được viết như thế này

function insertItem(array, action) {
return [
...array.slice(0, action.index),
action.item,
...array.slice(action.index)
]
}

function removeItem(array, action) {
return [...array.slice(0, action.index), ...array.slice(action.index + 1)]
}

Tuy nhiên, hãy nhớ rằng điều quan trọng là tham chiếu trong bộ nhớ ban đầu không bị sửa đổi. Miễn là chúng tôi tạo một bản sao trước, chúng tôi có thể thay đổi bản sao một cách an toàn. Lưu ý rằng điều này đúng với cả mảng và đối tượng, nhưng các giá trị lồng nhau vẫn phải được cập nhật bằng cùng một quy tắc

Điều này có nghĩa là chúng ta cũng có thể viết các hàm chèn và xóa như thế này

function updateVeryNestedField(state, action) {
return {
...state,
first: {
...state.first,
second: {
...state.first.second,
[action.someId]: {
...state.first.second[action.someId],
fourth: action.someValue
}
}
}
}
}
0

Chức năng loại bỏ cũng có thể được thực hiện như

function updateVeryNestedField(state, action) {
return {
...state,
first: {
...state.first,
second: {
...state.first.second,
[action.someId]: {
...state.first.second[action.someId],
fourth: action.someValue
}
}
}
}
}
1

Cập nhật một mục trong một mảng

Việc cập nhật một mục trong một mảng có thể được thực hiện bằng cách sử dụng

function updateNestedState(state, action) {
let nestedState = state.nestedState
// ERROR: this directly modifies the existing object reference - don't do this!
nestedState.nestedField = action.data

return {
...state,
nestedState
}
}
7, trả về một giá trị mới cho mục chúng tôi muốn cập nhật và trả về các giá trị hiện có cho tất cả các mục khác

function updateVeryNestedField(state, action) {
return {
...state,
first: {
...state.first,
second: {
...state.first.second,
[action.someId]: {
...state.first.second[action.someId],
fourth: action.someValue
}
}
}
}
}
3

Thư viện tiện ích cập nhật bất biến

Bởi vì việc viết mã cập nhật bất biến có thể trở nên tẻ nhạt, nên có một số thư viện tiện ích cố gắng trừu tượng hóa quy trình. Các thư viện này khác nhau về API và cách sử dụng, nhưng tất cả đều cố gắng cung cấp cách viết những cập nhật này ngắn gọn và súc tích hơn. Ví dụ: Immer làm cho các bản cập nhật bất biến trở thành một hàm đơn giản và các đối tượng JavaScript đơn giản

function updateVeryNestedField(state, action) {
return {
...state,
first: {
...state.first,
second: {
...state.first.second,
[action.someId]: {
...state.first.second[action.someId],
fourth: action.someValue
}
}
}
}
}
4

Một số, như dot-prop-immutable, lấy đường dẫn chuỗi cho các lệnh

function updateVeryNestedField(state, action) {
return {
...state,
first: {
...state.first,
second: {
...state.first.second,
[action.someId]: {
...state.first.second[action.someId],
fourth: action.someValue
}
}
}
}
}
5

Những thứ khác, như immutability-helper (một nhánh của addon React Immutability Helpers hiện không dùng nữa), sử dụng các giá trị lồng nhau và các hàm trợ giúp

function updateVeryNestedField(state, action) {
return {
...state,
first: {
...state.first,
second: {
...state.first.second,
[action.someId]: {
...state.first.second[action.someId],
fourth: action.someValue
}
}
}
}
}
6

Họ có thể cung cấp một giải pháp thay thế hữu ích để viết logic cập nhật bất biến thủ công

Có thể tìm thấy danh sách nhiều tiện ích cập nhật bất biến trong phần Danh mục Redux Addons

Đơn giản hóa các bản cập nhật không thay đổi với Bộ công cụ Redux

Gói Bộ công cụ Redux của chúng tôi bao gồm tiện ích

function updateNestedState(state, action) {
let nestedState = state.nestedState
// ERROR: this directly modifies the existing object reference - don't do this!
nestedState.nestedField = action.data

return {
...state,
nestedState
}
}
8 sử dụng Immer trong nội bộ. Do đó, bạn có thể viết các bộ giảm tốc có vẻ như ở trạng thái "đột biến", nhưng các bản cập nhật thực sự được áp dụng một cách bất biến

Điều này cho phép logic cập nhật bất biến được viết theo cách đơn giản hơn nhiều. Đây là những gì có thể trông giống như sử dụng

function updateNestedState(state, action) {
let nestedState = state.nestedState
// ERROR: this directly modifies the existing object reference - don't do this!
nestedState.nestedField = action.data

return {
...state,
nestedState
}
}
8

function updateNestedState(state, action) {
let nestedState = state.nestedState
// ERROR: this directly modifies the existing object reference - don't do this!
nestedState.nestedField = action.data

return {
...state,
nestedState
}
}
0

Điều này rõ ràng ngắn hơn nhiều và dễ đọc hơn. Tuy nhiên, điều này chỉ hoạt động chính xác nếu bạn đang sử dụng chức năng "ma thuật"

function updateNestedState(state, action) {
let nestedState = state.nestedState
// ERROR: this directly modifies the existing object reference - don't do this!
nestedState.nestedField = action.data

return {
...state,
nestedState
}
}
8 từ Bộ công cụ Redux bao bọc bộ giảm tốc này trong chức năng
function updateNestedState(state, action) {
// Problem: this only does a shallow copy!
let newState = { ...state }

// ERROR: nestedState is still the same object!
newState.nestedState.nestedField = action.data

return newState
}
1 của Immer. Nếu bộ giảm tốc này được sử dụng mà không có Immer, nó sẽ thực sự thay đổi trạng thái. Cũng không rõ ràng chỉ bằng cách nhìn vào mã mà chức năng này thực sự an toàn và cập nhật trạng thái một cách bất biến. Vui lòng đảm bảo rằng bạn hiểu đầy đủ các khái niệm về cập nhật bất biến. Nếu bạn sử dụng điều này, có thể hữu ích khi thêm một số nhận xét vào mã của bạn để giải thích các bộ giảm tốc của bạn đang sử dụng Bộ công cụ Redux và Immer

Ngoài ra, tiện ích

function updateNestedState(state, action) {
// Problem: this only does a shallow copy!
let newState = { ...state }

// ERROR: nestedState is still the same object!
newState.nestedState.nestedField = action.data

return newState
}
2 của Redux Toolkit sẽ tự động tạo các trình tạo hành động và các loại hành động dựa trên các hàm rút gọn mà bạn cung cấp, với cùng khả năng cập nhật do Immer cung cấp bên trong

Làm cách nào để thay đổi giá trị trong JavaScript đối tượng lồng nhau?

Cách cập nhật các thuộc tính lồng nhau trong một đối tượng trạng thái trong React. .
Truyền một hàm cho setState để có quyền truy cập vào đối tượng trạng thái hiện tại
Sử dụng cú pháp lây lan (. ) để tạo một bản sao nông của đối tượng và các thuộc tính lồng nhau
Ghi đè các thuộc tính bạn cần cập nhật

Làm cách nào để cập nhật một đối tượng bên trong một đối tượng JavaScript?

Để cập nhật một đối tượng trong một mảng JavaScript, bạn có thể sử dụng phương thức “findIndex()” để thực thi từng phần tử mảng và cập nhật các giá trị đối tượng tương ứng, phương thức vòng lặp “for” để lặp qua một mảng và cập nhật giá trị đã chỉ định và “map

Cách cập nhật khóa đối tượng

Để cập nhật tất cả các giá trị trong một đối tượng. .
Sử dụng đối tượng. keys() để lấy một mảng các khóa của đối tượng
Lặp lại mảng bằng phương thức forEach() và cập nhật từng giá trị
Sau lần lặp cuối cùng, tất cả các giá trị trong đối tượng sẽ được cập nhật

Làm cách nào để lấy giá trị đối tượng lồng nhau động trong JavaScript?

Bạn có thể truy cập động các thuộc tính đối tượng lồng nhau trong JavaScript bằng cách sử dụng dấu ngoặc vuông . Bạn cần sử dụng nhiều dấu ngoặc vuông cho một đối tượng lồng nhau. Tôi có một đối tượng lồng nhau với thuộc tính tên cũng là một đối tượng. Thuộc tính tên chứa hai thuộc tính lồng nhau.