В этой статье вы получите представление о том, как работает компонент React, и о методе сравнения, который он использует, чтобы определить, когда следует повторно отображать пользовательский интерфейс.
Простой пример, который мы используем: нажатие кнопки приведет к повторному рендерингу компонента, и вы увидите журнал в консоли.
const [state, setState] = useState() // to track how many time the component renders console.log('render at ' + new Date().toLocaleTimeString()) return ( <Button onClick={() => setState('something')} /> )
Поэтому большинство людей думают, что вызов setState
всегда будет вызывать повторную визуализацию компонента.
Удивительно, но в некоторых случаях это не так. На самом деле компонент React выполняет поверхностное сравнение, чтобы проверить, изменился ли state
перед фактическим рендерингом.
Прежде всего, давайте посмотрим, как JavaScript выполняет строгое сравнение (тройное равенство):
true === true // true false === false // true 0 === 0 // true Infinity === Infinity // true "string" === "string" // true null === null // true undefined === undefined // true NaN === NaN // false [] === [] // false [1, "string"] === [1, "string"] // false {} === {} // false {id: 9} === {id : 9} // false
Поверхностное сравнение аналогично строгому сравнению при сравнениипримитивных типов данных, объектов и массивов. Единственным исключением является NaN
На самом деле ReactJS использует Object.is
для сравнения состояния и свойств.
NaN === NaN // false Object.is(NaN, NaN) // true
Пример с примитивными типами данных
const [name, setName] = useState("Jenny") // to track how many time the component renders console.log('render at ' + new Date().toLocaleTimeString()) return ( <> <Button onClick={() => setName("Jenny")} /> <Button onClick={() => setName("Emily")} /> </> )
- нажатие на первую кнопку не вызовет повторную визуализацию компонента.
- щелчок по второй кнопке запустит повторную визуализацию компонента.
Object.is("Jenny", "Jenny") // true Object.is("Jenny", "Emily") // false
Пример с типами объектов
const [user, setUser] = useState({name: "Jenny"}) // to track how many time the component renders console.log('render at ' + new Date().toLocaleTimeString()) return ( <Button onClick={() => { const newUser = {name: "Jenny"} setUser(newUser) }/> )
Нажатие на кнопку вызовет повторную визуализацию компонента, даже если свойство name
из newUser
имеет то же значение, что и старое состояние.
Object.is("Jenny", "Jenny") // true Object.is({name: "Jenny"}, {name: "Jenny"}) // false
Ключевые выводы
ReactJS использует поверхностное сравнение вместо глубокого сравнения по соображениям производительности.
Поверхностное сравнение — это быстрый способ определить, различаются ли два объекта, сравнивая только их ссылки или примитивные значения, а не рекурсивно сравнивая их вложенные свойства. Это означает, что если два объекта имеют одинаковые свойства и значения, но не являются одним и тем же объектом, они не будут считаться равными при поверхностном сравнении.
С другой стороны, глубокое сравнение включает рекурсивное сравнение всех свойств объектов, что может занять много времени и ресурсов для больших или сложных объектов.