Shallow comparison là gì

Trong tài liệu về React này, người ta nói rằng

AgriculturalCompare thực hiện kiểm tra bình đẳng nông trên các đối tượng props và nextProps hiện tại cũng như trạng thái hiện tại và các đối tượng nextState.

Điều mà tôi không thể hiểu được là Nếu nó so sánh nông cạn các đối tượng thì phương thức shouldComponentUpdate sẽ luôn trả về true, như

Chúng ta không nên thay đổi các trạng thái.

và nếu chúng ta không thay đổi trạng thái thì phép so sánh sẽ luôn trả về false và do đó, bản cập nhật shouldComponent sẽ luôn trả về true. Tôi bối rối về cách nó hoạt động và làm thế nào chúng tôi sẽ ghi đè điều này để tăng hiệu suất.

So sánh nông không kiểm tra sự bình đẳng. Khi so sánh các giá trị vô hướng (số, chuỗi) nó sẽ so sánh các giá trị của chúng. Khi so sánh các đối tượng, nó không so sánh các thuộc tính của chúng - chỉ các tham chiếu của chúng được so sánh (ví dụ: "chúng có trỏ đến cùng một đối tượng không?).

Hãy xem xét hình dạng của uservật thể sau user = { name: "John", surname: "Doe"}

Ví dụ 1:   const user = this.state.user; user.name = "Jane"; console.log(user === this.state.user); // true

Lưu ý rằng bạn đã thay đổi tên người dùng. Ngay cả với các đối tượng thay đổi này là bằng nhau. Họ tham khảo là hoàn toàn giống nhau.

Ví dụ 2:   const user = clone(this.state.user); console.log(user === this.state.user); // false

Bây giờ, không có bất kỳ thay đổi nào đối với thuộc tính đối tượng, chúng hoàn toàn khác nhau. Bằng cách sao chép đối tượng gốc, bạn tạo ra bản sao mới, với các tham chiếu khác nhau.

Hàm sao chép có thể trông như thế này (cú pháp ES6) const clone = obj => Object.assign({}, ...obj);

So sánh nông là cách hiệu quả để phát hiện các thay đổi. Nó hy vọng bạn không thay đổi dữ liệu.

So sánh nông là khi các thuộc tính của đối tượng được so sánh được thực hiện bằng cách sử dụng "===" hoặc bình đẳng nghiêm ngặt và sẽ không tiến hành so sánh sâu hơn vào các thuộc tính. ví dụ // a simple implementation of the shallowCompare.// only compares the first level properties and hence shallow.// state updates(theoretically) if this function returns true.function shallowCompare(newObj, prevObj){ for (key in newObj){ if(newObj[key] !== prevObj[key]) return true; } return false; } // var game_item = { game: "football", first_world_cup: "1930", teams: { North_America: 1, South_America: 4, Europe: 8 } } // Case 1:// if this be the object passed to setStatevar updated_game_item1 = { game: "football", first_world_cup: "1930", teams: { North_America: 1, South_America: 4, Europe: 8 } } shallowCompare(updated_game_item1, game_item); // true - meaning the state                                               // will update.

Mặc dù cả hai đối tượng có vẻ giống nhau, nhưng game_item.teamskhông phải là tham chiếu giống nhau updated_game_item.teams. Để 2 đối tượng giống nhau, chúng nên chỉ vào cùng một đối tượng. Do đó, điều này dẫn đến trạng thái được đánh giá là cập nhật // Case 2:// if this be the object passed to setStatevar updated_game_item2 = { game: "football", first_world_cup: "1930", teams: game_item.teams } shallowCompare(updated_game_item2, game_item); // false - meaning the state                                               // will not update.

Lần này mọi thuộc tính trả về true cho phép so sánh chặt chẽ vì thuộc tính nhóm trong đối tượng mới và cũ trỏ đến cùng một đối tượng. // Case 3:// if this be the object passed to setStatevar updated_game_item3 = { first_world_cup: 1930} shallowCompare(updated_game_item3, game_item); // true - will update

Các updated_game_item3.first_world_cupbất động sản không đánh giá nghiêm ngặt như 1930 là một con số trong khi game_item.first_world_cuplà một chuỗi. Nếu sự so sánh bị lỏng lẻo (==) thì điều này sẽ trôi qua. Tuy nhiên, điều này cũng sẽ dẫn đến cập nhật trạng thái.

Ghi chú bổ sung:

  1. Thực hiện so sánh sâu là vô nghĩa vì nó sẽ ảnh hưởng đáng kể đến hiệu suất nếu đối tượng trạng thái được lồng sâu vào nhau. Nhưng nếu nó không quá lồng nhau và bạn vẫn cần so sánh sâu, hãy triển khai nó trong shouldComponentUpdate và kiểm tra xem điều đó có đủ hay không.
  2. Bạn chắc chắn có thể thay đổi đối tượng trạng thái trực tiếp nhưng trạng thái của các thành phần sẽ không bị ảnh hưởng, vì nó trong luồng phương thức setState mà phản ứng thực hiện các móc chu kỳ cập nhật thành phần. Nếu bạn cập nhật trực tiếp đối tượng trạng thái để cố tình tránh các móc vòng đời của thành phần, thì có lẽ bạn nên sử dụng một biến hoặc đối tượng đơn giản để lưu trữ dữ liệu chứ không phải đối tượng trạng thái.
So sánh nông hoạt động bằng cách kiểm tra xem hai giá trị có bằng nhau không trong trường hợp các kiểu nguyên thủy như chuỗi, số và trong trường hợp đối tượng, nó chỉ kiểm tra tham chiếu . Vì vậy, nếu bạn so sánh nông một đối tượng lồng nhau sâu, nó sẽ chỉ kiểm tra tham chiếu chứ không phải các giá trị bên trong đối tượng đó.

Ngoài ra còn có lời giải thích kế thừa về so sánh nông trong React:

AgriculturalCompare thực hiện kiểm tra bình đẳng nông trên các đối tượng props và nextProps hiện tại cũng như trạng thái hiện tại và các đối tượng nextState.
Nó thực hiện điều này bằng cách lặp lại các khóa của các đối tượng được so sánh và trả về true khi giá trị của một khóa trong mỗi đối tượng không hoàn toàn bằng nhau.

UPD : Tài liệu hiện tại nói về so sánh nông:

Nếu hàm render () của thành phần React của bạn hiển thị cùng một kết quả với cùng một trạng thái và đạo cụ, bạn có thể sử dụng React.PureComponent để tăng hiệu suất trong một số trường hợp.
ShouldComponentUpdate () của React.PureComponent chỉ so sánh nông các đối tượng. Nếu chúng chứa các cấu trúc dữ liệu phức tạp, nó có thể tạo ra âm tính giả cho sự khác biệt sâu hơn. Chỉ mở rộng PureComponent khi bạn mong đợi có các đạo cụ và trạng thái đơn giản hoặc sử dụng forceUpdate () khi bạn biết cấu trúc dữ liệu sâu đã thay đổi

UPD2: Tôi nghĩ Hòa giải cũng là một chủ đề quan trọng để hiểu được so sánh nông cạn.

Đoạn mã bằng nông của @supi ở trên ( https://stackoverflow.com/a/51343585/800608 ) không thành công nếu prevObjcó khóa newObjkhông có. Đây là một cách triển khai cần tính đến điều đó: const shallowEqual = (objA, objB) => { if (!objA || !objB) { return objA === objB } return !Boolean( Object      .keys(Object.assign({}, objA, objB)) .find((key) => objA[key] !== objB[key]) ) }

Lưu ý rằng điều trên không hoạt động trong Explorer mà không có polyfills.

Có một triển khai với các ví dụ. const isObject = value => typeof value === 'object' && value !== null; const compareObjects = (A, B) => { const keysA = Object.keys(A); const keysB = Object.keys(B); if (keysA.length !== keysB.length) { return false; } return !keysA.some(key => !B.hasOwnProperty(key) || A[key] !== B[key]); }; const shallowEqual = (A, B) => { if (A === B) { return true; } if ([A, B].every(Number.isNaN)) { return true; } if (![A, B].every(isObject)) { return false; } return compareObjects(A, B); }; const a = { field: 1 }; const b = { field: 2 }; const c = { field: { field: 1 } }; const d = { field: { field: 1 } }; console.log(shallowEqual(1, 1)); // trueconsole.log(shallowEqual(1, 2)); // falseconsole.log(shallowEqual(null, null)); // trueconsole.log(shallowEqual(NaN, NaN)); // trueconsole.log(shallowEqual([], [])); // trueconsole.log(shallowEqual([1], [2])); // falseconsole.log(shallowEqual({}, {})); // trueconsole.log(shallowEqual({}, a)); // falseconsole.log(shallowEqual(a, b)); // falseconsole.log(shallowEqual(a, c)); // falseconsole.log(shallowEqual(c, d)); // false Chạy đoạn mãẨn kết quảMở rộng đoạn mã

Video liên quan