How to use the setstate callback in react

Giriş

React, bileşenleri sınıf ve fonksiyon olarak tanımlamanızı sağlar. Sınıf olarak tanımlanan bileşenler, fonksiyon olanlara göre daha fazla özellik sunar. Bu özellikler sayfanın ilerleyen bölümlerinde daha detaylı şekilde ele alınacaktır.


React bileşen sınıfı oluşturmak için, sınıfınızı ‘ten türetmeniz gerekir:

‘ten türetilen sınıflarda, zorunlu olarak tanımlamanız gereken metot sadece ‘dır. Bu sayfada tanıtılacak olan diğer metotlar ise opsiyoneldir.

yerine kendi ürettiğiniz temel sınıfları oluşturmanızı kesinlikle tavsiye etmiyoruz. Çünkü React bileşenlerinde, kodun tekrar kullanılabilirliği kalıtım yoluyla değil, kompozisyon ile sağlanır.

Bir Bileşenin Yaşam Döngüsü

Her bileşen, belirli durumlarda çalıştırabileceğiniz birkaç “yaşam döngüsü metodu” (lifecycle methods) sunar. Bu metodları hatırlamak için, yaşam döngüsü diyagramını kullanabilirsiniz. Aşağıdaki listede, yaygın olarak kullanılan yaşam döngüsü metodları kalın harfler ile belirtilmiştir. Geri kalan metotlar, daha nadir kullanımlar için uygundur.

Eklenmesi

Bir bileşenin oluşumundan ve DOM’a eklenmesine kadar geçen süreç içerisinde çağrılan metotlar, sırasıyla aşağıdaki gibi belirlenmiştir:

Güncellenmesi

Bileşenin güncellemesi, kendi props’u veya state’i üzerindeki değişikliklerden oluşabilir. Bir bileşen tekrar render edildiğinde çağrılan metotlar sırasıyla aşağıdaki gibidir:

Bir bileşen, DOM’dan çıkarıldığında bu metot çalışır:

componentWillUnmount()

Hatanın Yakalanması

Aşağıdaki metotlar; render esnasında, yaşam döngüsü metodunda veya herhangi bir alt bileşenin constructor’ında bir hata oluştuğunda çağrılmaktadır:

Извлечённые уроки

Для любых изменяемых данных в React-приложении должен быть один «источник истины». Обычно состояние сначала добавляется к компоненту, которому оно требуется для рендера. Затем, если другие компоненты также нуждаются в нём, вы можете поднять его до ближайшего общего предка. Вместо того, чтобы пытаться синхронизировать состояние между различными компонентами, вы должны полагаться на .

Для подъёма состояния приходится писать больше «шаблонного» кода, чем при подходах с двусторонней привязкой данных, но мы получаем преимущество в виде меньших затрат на поиск и изолирование багов. Так как любое состояние «живёт» в каком-нибудь компоненте, и только этот компонент может его изменить, количество мест с возможными багами значительно уменьшается. Кроме того, вы можете реализовать любую пользовательскую логику для отклонения или преобразования данных, введённых пользователем.

Если что-то может быть вычислено из пропсов или из состояния, то скорее всего оно не должно находиться в состоянии. Например, вместо сохранения и , мы сохраняем только последнюю введённую температуру () и её шкалу (). Значение другого поля ввода можно всегда вычислить из них в методе . Это позволяет очистить или применить округление к значению другого поля, не теряя при этом точности значений, введённых пользователем.

Когда вы видите, что в UI что-то отображается неправильно, то можете воспользоваться расширением React Developer Tools. С помощью него можно проверить пропсы и перемещаться по дереву компонентов вверх до тех пор, пока не найдёте тот компонент, который отвечает за обновление состояния. Это позволяет отследить источник багов:

其他的 API

和上述那些由 React 替你呼叫的生命週期方法不同,以下介紹的方法是你可以從你的 component 呼叫的。

只有兩個方法: 和 。

會將改變排進一個 queue 中,並告知 React 這個 component 以及它的 children 需要用更新後的 state 重新 render。這是你會在事件處理和伺服器回應用來更新使用者介面最主要的方法。

請把 想成一個請求而非一個馬上對 component 進行更新的指令。為了達到更好的效能,React 也許會延遲這個請求,然後一次更新數個 component。React 並不保證 state 的改變會馬上發生。

並不會總是馬上更新 component。它有可能會將更新分批處理更新或延遲到稍後才更新。這使得在呼叫 後讀取 成為一個潛在的問題。因此請不要這麼做。相反的,請使用 或一個 callback()。不論你使用哪一個,React 都保證它會在更新後被觸發。如果你需要基於先前的 state 來設定 state 的話,請閱讀以下關於 的參數。

除非 回傳 , 一定會導致重新 render。如果你有使用 mutable object,或者你無法在 裡面建立條件式 render 的邏輯的話,只在新的 state 和先前的 state 不同時呼叫 將會避免不必要的重新 render。

這個方法的第一個參數是一個帶有如下的形式的 function:

是當某個改變正在被應用時對 component state 的一個參考。它不應該直接被 mutate。相反的,任何改變都應該用一個基於 和 的 input 所建立的新的 object 來表示。例如,假設我們想要使用 來增加 state 中的某個值的話:

被 updater function 所接受的 和 兩者都保證一定會被更新到最新的狀態。Updater 的 output 會被和 淺層合併。

的第二個參數是一個非必要、選擇性的 callback function。它會在 完成且 component 被重新 render 後被執行。一般來說如果你要使用這樣的邏輯的話,我們比較推薦你使用 。

你可以選擇將一個 object(而非 function)作為第一個參數傳給 :

這會將 淺層合併至新的 state 中。舉個例子,假設你想調整購物車中物品的數量:

這種形式的 也是同步的,而同樣一個週期中的多次呼叫有可能會被結合成一批做處理。例如,假設你想在同一個週期中增加某個物品的數量超過一次的話,這樣做的結果會和以下程式碼相同:

在同一個週期中,後續的呼叫會覆蓋之前的呼叫所產生的值,所以物品的數量只會被增加一次。如果下個 state 是根據目前的 state 而決定的話,我們比較建議你用 updater function 來更新 state:

想了解更多細節,請參考:

  • State 和生命週期指南
  • 深入解析:為什麼 的呼叫會批次處理?什麼時候會如此?

當你的 component 的 state 或 prop 改變的時候,你的 component 的預設行為是會重新 render。如果你的 方法還需要其他資料的話,你可以藉由呼叫 來告訴 React 這個 component 需要重新 render。

呼叫 會導致 被呼叫於該 component 並跳過 。這會觸發 children component 正常的生命週期方法,包含每個 child 的 方法。React 依然只會在 markup 改變時更新 DOM。

正常情況來說你應該避免使用 並只從 中的 和 讀取。

概觀

在 React 中,你可以將 component 定義成 class 或 function。目前,被定義為 class 的 component 提供了更多功能,我們將會在本章節中逐一介紹。要定義一個 React component class,你需要繼承(extend):

在 的 subclass 中唯一一個你必須定義的方法是 。本章節中所有其他的方法都並非絕對必要。

我們強烈建議你不要建立自己的 base component class。 在 React component 中,程式的重複使用性主要是透過組合而非繼承來完成的。

Component 生命週期

每一個 component 都有數個 「生命週期方法」,你可以 override 這些方法,以便在開發過程中某些特定的時刻執行某些程式。你可以使用這個生命週期表作為速查表。 以下,常用的生命週期方法將會以粗體表達。其餘的生命週期方法則相對較少。

當一個 component 被從 DOM 中移除時,這個方法將會被呼叫:

componentWillUnmount()

錯誤處理

當一個 component 在 render 的過程、生命週期、或在某個 child component 的 constructor 中發生錯誤時,這些方法會被呼叫:

Інші API

На відміну від вищенаведених методів життєвого циклу (які React викликає для вас), ви можете викликати методи нижче з ваших компонентів.

Їх всього два: і .

ставить в чергу оновлення стану компонента і повідомляє React, що цей компонент і його нащадки мають бути повторно відрендерені з оновленим станом. Це основний метод, який ви використовуєте для оновлення інтерфейсу користувача у відповідь на обробники подій і відповіді сервера.

Думайте про як про запит, а не як про команду, що має бути негайно виконана для оновлення компонента. Для кращої наочної продуктивності, React може відкласти виклик і тоді оновити кілька компонентів за один прохід. React не гарантує негайного застосування змін стану.

не завжди відразу оновлює компонент. Цей метод може групувати чи відкладати оновлення на потім. Це робить зчитування відразу після виклику потенційною пасткою. Натомість, використовуйте чи функцію зворотнього виклику (), обидва підходи гарантовано запустяться після застосування оновлення. Якщо вам потрібно оновити стан на основі поперенього стану, прочитайте про аргумент нижче.

завжди призводить до повторного рендерингу за умови, що не повертає . Якщо використовуються змінні об’єкти і логіка умовного рендерингу не може бути реалізована у , виклик тільки тоді, коли новий стан відрізняється від попереднього, може запобігти непотрібних повторних рендерингів.

Перший аргумент — це функція визначена як:

— це посилання на стан компонента в момент часу, коли зміна застосовується. Воно не має змінюватись напряму. Замість цього, зміни повинні бути представлені шляхом створення нового об’єкту на основі вхідних даних із та . Наприклад, ми хочемо збільшити значення в стані на :

Як , так і , отримані функцією оновлення, гарантовано будуть в актуальному стані. Результат функції оновлення буде поверхово об’єднаний із .

Другий параметр — це необов’язкова функція зворотнього виклику, яка буде виконана після того, як завершив роботу і компонент повторно відрендерився. Зазвичай ми радимо використовувати для подібної логіки.

Ви можете передати в першим аргументом об’єкт, а не функцію:

Це виконає поверхове об’єднання в новий стан, наприклад, для зміни кількості товарів у корзині:

Ця форма запису також асинхронна і кілька викликів впродовж одного циклу можуть бути згруповані в один. Наприклад, якщо ви спробуєте інкрементувати кількість елементів більше, ніж один раз в одному циклі, результат буде еквівалентний:


Наступні виклики перезапишуть попередні значення в цьому циклі і кількість буде інкрементована лише раз. Якщо наступний стан залежить від поточного, ми радимо використовувати форму з функцією оновлення:

Для більш детальної інформації перегляньте:

  • Стан та життєвий цикл
  • В подробицях: Коли і чому виклики групуються?

За замовчуванням, коли стан чи пропси вашого компонента змінюються, він буде повторно відрендерений. Якщо ваш метод залежить від деяких інших даних, за допомогою виклику ви можете вказати React, що компонент потребує повторного рендерингу.

Виклик спричинить виклик у компоненті з пропуском . Це викличе звичайні методи життєвого циклу в дочірніх компонентах, включно з для кожного нащадка. React, як і раніше, оновить DOM лише у випадку зміни розмітки.

Зазвичай краще уникати всіх використань і тільки зчитувати і в .

The Data Flows Down

Neither parent nor child components can know if a certain component is stateful or stateless, and they shouldn’t care whether it is defined as a function or a class.

This is why state is often called local or encapsulated. It is not accessible to any component other than the one that owns and sets it.

A component may choose to pass its state down as props to its child components:

The component would receive the in its props and wouldn’t know whether it came from the ’s state, from the ’s props, or was typed by hand:

This is commonly called a “top-down” or “unidirectional” data flow. Any state is always owned by some specific component, and any data or UI derived from that state can only affect components “below” them in the tree.

If you imagine a component tree as a waterfall of props, each component’s state is like an additional water source that joins it at an arbitrary point but also flows down.

To show that all components are truly isolated, we can create an component that renders three s:

Each sets up its own timer and updates independently.

In React apps, whether a component is stateful or stateless is considered an implementation detail of the component that may change over time. You can use stateless components inside stateful components, and vice versa.

Жизненный цикл компонента

Самой важной для понимания концепцией в этой статье является. Её суть ясна из названия — она описывает жизнь компонента

Как и мы, компоненты рождаются, что-то делают во время своего пребывания на бренной земле (сервере), а потом умирают.

Однако жизненные этапы компонентов немного отличаются от наших. Вот как они выглядят:

Каждый раскрашенный горизонтальный прямоугольник отражает метод жизненного цикла (за исключением «React обновляет DOM и ссылки»). Столбцы отражают разные этапы жизни компонента.

Компонент может находиться только на одном этапе. Всё начинается с монтирования и продолжается обновлением. Компонент постоянно обновляется, пока не будет удалён из виртуального DOM. Затем компонент переходит на этап размонтирования и удаляется из DOM.

Frontend developer (Vue)

Sportmaster Lab, Липецк, до 130 000 ₽

tproger.ru

Вакансии на tproger.ru

Методы жизненного цикла позволяют запускать код в определённые моменты жизни компонента или в ответ на какие-то изменения в ней.

Пройдёмся по каждому этапу жизни компонента и связанным методам.

Монтирование

Так как компоненты на основе классов являются классами (отсюда и название), первый запускаемый метод — это . Как правило, в мы инициализируем состояние компонента.

Затем компонент запускает . Опустим этот метод, так как он не очень полезный.

После этого наступает очередь метода , который возвращает JSX. Теперь React «монтируется» в DOM.

Наконец, запускается метод . Здесь выполняются все асинхронные вызовы к базам данных или напрямую управляется DOM. Компонент рождён.

Обновление

Этот этап запускается при каждом изменении состояния или свойств. Как и при монтировании, вызывается метод , но в этот раз без .

Затем запускается . Здесь можно сравнивать старые свойства или состояния с новым набором свойств или состояний. Можно указать, нужно ли заново отображать компонент, вернув или . Это позволит сделать приложение более эффективным за счёт уменьшения количества лишних отображений. Если возвращает , на этом этап обновлений завершается.

В противном случае React заново отобразится, а затем запускается . Этот метод тоже не очень полезен. Далее React запускает . Как и , его можно использовать для асинхронных вызовов или управления DOM.

Размонтирование

Компонент прожил хорошую жизнь, однако всё хорошее рано или поздно кончается. Размонтирование — последний этап жизни компонента. При удалении компонента из DOM React запускает прямо перед удалением. Этот метод используется для закрытия всех открытых соединений вроде веб-сокетов или тайм-аутов.

Другие методы жизненного цикла

Прежде чем мы перейдём к другой теме, давайте вскользь упомянем и .

— метод, который напрямую вызывает повторное отображение. Хотя у него и есть несколько применений, обычно его следует избегать.

С другой стороны, — метод жизненного цикла, который не совсем является его частью. Если в компоненте возникает ошибка, запускается  и вы получаете возможность обновить состояние, чтобы показать, что произошла ошибка. Используйте этот метод почаще.

Следующий фрагмент кода с CodePen показывает этапы стадии монтирования:

Вывод:

Понимание жизненного цикла компонентов и методов React позволит поддерживать правильную передачу данных между компонентами и обрабатывать события в приложении.

参考

常用的生命周期方法

本节中的方法涵盖了创建 React 组件时能遇到的绝大多数用例。想要更好了解这些方法,可以参考生命周期图谱。

方法是 class 组件中唯一必须实现的方法。

当 被调用时,它会检查 和 的变化并返回以下类型之一:

  • React 元素。通常通过 JSX 创建。例如, 会被 React 渲染为 DOM 节点, 会被 React 渲染为自定义组件,无论是 还是 均为 React 元素。
  • 数组或 fragments。 使得 render 方法可以返回多个元素。欲了解更多详细信息,请参阅 fragments 文档。
  • Portals。可以渲染子节点到不同的 DOM 子树中。欲了解更多详细信息,请参阅有关 portals 的文档
  • 字符串或数值类型。它们在 DOM 中会被渲染为文本节点
  • 布尔类型或 。什么都不渲染。(主要用于支持返回 的模式,其中 test 为布尔类型。)

函数应该为纯函数,这意味着在不修改组件 state 的情况下,每次调用时都返回相同的结果,并且它不会直接与浏览器交互。

如需与浏览器进行交互,请在 或其他生命周期方法中执行你的操作。保持 为纯函数,可以使组件更容易思考。

如果不初始化 state 或不进行方法绑定,则不需要为 React 组件实现构造函数。

在 React 组件挂载之前,会调用它的构造函数。在为 React.Component 子类实现构造函数时,应在其他语句之前前调用 。否则, 在构造函数中可能会出现未定义的 bug。

通常,在 React 中,构造函数仅用于以下两种情况:

  • 通过给 赋值对象来初始化内部 state。
  • 为事件处理函数绑定实例

在 函数中不要调用 方法。如果你的组件需要使用内部 state,请直接在构造函数中为 赋值初始 state:

只能在构造函数中直接为 赋值。如需在其他方法中赋值,你应使用 替代。

要避免在构造函数中引入任何副作用或订阅。如遇到此场景,请将对应的操作放置在 中。

会在组件挂载后(插入 DOM 树中)立即调用。依赖于 DOM 节点的初始化应该放在这里。如需通过网络请求获取数据,此处是实例化请求的好地方。

这个方法是比较适合添加订阅的地方。如果添加了订阅,请不要忘记在 里取消订阅


你可以在 里直接调用 。它将触发额外渲染,但此渲染会发生在浏览器更新屏幕之前。如此保证了即使在 两次调用的情况下,用户也不会看到中间状态。请谨慎使用该模式,因为它会导致性能问题。通常,你应该在 中初始化 state。如果你的渲染依赖于 DOM 节点的大小或位置,比如实现 modals 和 tooltips 等情况下,你可以使用此方式处理

会在更新后会被立即调用。首次渲染不会执行此方法。

当组件更新后,可以在此处对 DOM 进行操作。如果你对更新前后的 props 进行了比较,也可以选择在此处进行网络请求。(例如,当 props 未发生变化时,则不会执行网络请求)。

你也可以在 中直接调用 ,但请注意它必须被包裹在一个条件语句里,正如上述的例子那样进行处理,否则会导致死循环。它还会导致额外的重新渲染,虽然用户不可见,但会影响组件性能。不要将 props “镜像”给 state,请考虑直接使用 props。 欲了解更多有关内容,请参阅为什么 props 复制给 state 会产生 bug。

如果组件实现了 生命周期(不常用),则它的返回值将作为 的第三个参数 “snapshot” 参数传递。否则此参数将为 undefined。

会在组件卸载及销毁之前直接调用。在此方法中执行必要的清理操作,例如,清除 timer,取消网络请求或清除在 中创建的订阅等。

中不应调用 ,因为该组件将永远不会重新渲染。组件实例卸载后,将永远不会再挂载它。

不常用的生命周期方法

本节中的生命周期方法并不太常用。它们偶尔会很方便,但是大部分情况下组件可能都不需要它们。你可以在生命周期图谱中,选择“显示不常用的生命周期”复选框,即可看到下述相关方法。

根据 的返回值,判断 React 组件的输出是否受当前 state 或 props 更改的影响。默认行为是 state 每次发生变化组件都会重新渲染。大部分情况下,你应该遵循默认行为。

当 props 或 state 发生变化时, 会在渲染执行之前被调用。返回值默认为 true。首次渲染或使用 时不会调用该方法。

此方法仅作为性能优化的方式而存在。不要企图依靠此方法来“阻止”渲染,因为这可能会产生 bug。你应该考虑使用内置的 组件,而不是手动编写 。 会对 props 和 state 进行浅层比较,并减少了跳过必要更新的可能性。

如果你一定要手动编写此函数,可以将 与 以及 与 进行比较,并返回 以告知 React 可以跳过更新。请注意,返回 并不会阻止子组件在 state 更改时重新渲染。

我们不建议在 中进行深层比较或使用 。这样非常影响效率,且会损害性能。

目前,如果 返回 ,则不会调用 , 和 。后续版本,React 可能会将 视为提示而不是严格的指令,并且,当返回 时,仍可能导致组件重新渲染。

会在调用 render 方法之前调用,并且在初始挂载及后续更新时都会被调用。它应返回一个对象来更新 state,如果返回 null 则不更新任何内容。

此方法适用于,即 state 的值在任何时候都取决于 props。例如,实现 组件可能很方便,该组件会比较当前组件与下一组件,以决定针对哪些组件进行转场动画。

派生状态会导致代码冗余,并使组件难以维护。 确保你已熟悉这些简单的替代方案:

  • 如果你需要执行副作用(例如,数据提取或动画)以响应 props 中的更改,请改用 。
  • 如果只想在 prop 更改时重新计算某些数据,。
  • 如果你想在 prop 更改时“重置”某些 state,请考虑使组件或 代替。

此方法无权访问组件实例。如果你需要,可以通过提取组件 props 的纯函数及 class 之外的状态,在和其他 class 方法之间重用代码。

请注意,不管原因是什么,都会在每次渲染前触发此方法。这与 形成对比,后者仅在父组件重新渲染时触发,而不是在内部调用 时。

在最近一次渲染输出(提交到 DOM 节点)之前调用。它使得组件能在发生更改之前从 DOM 中捕获一些信息(例如,滚动位置)。此生命周期的任何返回值将作为参数传递给 。

此用法并不常见,但它可能出现在 UI 处理中,如需要以特殊方式处理滚动位置的聊天线程等。

应返回 snapshot 的值(或 )。

例如:

在上述示例中,重点是从 读取 属性,因为 “render” 阶段生命周期(如 )和 “commit” 阶段生命周期(如 和 )之间可能存在延迟。

Error boundaries

Error boundaries 是 React 组件,它会在其子组件树中的任何位置捕获 JavaScript 错误,并记录这些错误,展示降级 UI 而不是崩溃的组件树。Error boundaries 组件会捕获在渲染期间,在生命周期方法以及其整个树的构造函数中发生的错误。

如果 class 组件定义了生命周期方法 或 中的任何一个(或两者),它就成为了 Error boundaries。通过生命周期更新 state 可让组件捕获树中未处理的 JavaScript 错误并展示降级 UI。

仅使用 Error boundaries 组件来从意外异常中恢复的情况;不要将它们用于流程控制。

欲了解更多详细信息,请参阅 React 16 中的错误处理。

此生命周期会在后代组件抛出错误后被调用。 它将抛出的错误作为参数,并返回一个值以更新 state

此生命周期在后代组件抛出错误后被调用。 它接收两个参数:

  1. —— 抛出的错误。
  2. —— 带有 key 的对象,其中包含。

会在“提交”阶段被调用,因此允许执行副作用。 它应该用于记录错误之类的情况:

过时的生命周期方法

以下生命周期方法标记为“过时”。这些方法仍然有效,但不建议在新代码中使用它们。参阅此博客文章以了解更多有关迁移旧版生命周期方法的信息。

在挂载之前被调用。它在 之前调用,因此在此方法中同步调用 不会触发额外渲染。通常,我们建议使用 来初始化 state。

避免在此方法中引入任何副作用或订阅。如遇此种情况,请改用 。

此方法是服务端渲染唯一会调用的生命周期函数。

会在已挂载的组件接收新的 props 之前被调用。如果你需要更新状态以响应 prop 更改(例如,重置它),你可以比较 和 并在此方法中使用 执行 state 转换。

请注意,如果父组件导致组件重新渲染,即使 props 没有更改,也会调用此方法。如果只想处理更改,请确保进行当前值与变更值的比较。

在过程中,React 不会针对初始 props 调用 。组件只会在组件的 props 更新时调用此方法。调用 通常不会触发 。

当组件收到新的 props 或 state 时,会在渲染之前调用 。使用此作为在更新发生之前执行准备更新的机会。初始渲染不会调用此方法。

注意,你不能此方法中调用 ;在 返回之前,你也不应该执行任何其他操作(例如,dispatch Redux 的 action)触发对 React 组件的更新

通常,此方法可以替换为 。如果你在此方法中读取 DOM 信息(例如,为了保存滚动位置),则可以将此逻辑移至 中。

Sınıf Bileşeninin Değişkenleri

, bileşen sınıfının varsayılan prop değerlerini atamak için sınıf içerisinde değişken olarak tanımlanabilir. Bu değişken, tanımlı olmayan prop değerleri için kullanılır. Null değeri içeren prop’lar için kullanılmaz. Örneğin:

Eğer bileşene değeri aktarılmazsa, varsayılan olarak atanacaktır:

Bunun aksine değeri null olarak atanmışsa, değişmeden null olarak kalacaktır:

değişkeni, hata ayıklama mesajlarında kullanılır. Genellikle açık olarak bu değişkene atama yapmanıza gerek yoktur. Çünkü tanımlandığı fonksiyon veya sınıf bileşeninin isminden oluşturulmaktadır. Hata ayıklama işleminde farklı bir isim kullanmak istiyorsanız, elbette bu değişkeni açık bir şekilde tanımlayıp atama yapabilirsiniz. Ayrıca high-order bir bileşen oluştururken de kullanabilirsiniz. yazısından daha detaylı bilgi edinebilirsiniz.

其他 API

不同于上述生命周期方法(React 主动调用),以下方法是你可以在组件中调用的方法。

只有两个方法: 和 。

将对组件 state 的更改排入队列,并通知 React 需要使用更新后的 state 重新渲染此组件及其子组件。这是用于更新用户界面以响应事件处理器和处理服务器数据的主要方式

将 视为请求而不是立即更新组件的命令。为了更好的感知性能,React 会延迟调用它,然后通过一次传递更新多个组件。React 并不会保证 state 的变更会立即生效。

并不总是立即更新组件。它会批量推迟更新。这使得在调用 后立即读取 成为了隐患。为了消除隐患,请使用 或者 的回调函数(),这两种方式都可以保证在应用更新后触发。如需基于之前的 state 来设置当前的 state,请阅读下述关于参数 的内容。

除非 返回 ,否则 将始终执行重新渲染操作。如果可变对象被使用,且无法在 中实现条件渲染,那么仅在新旧状态不一时调用 可以避免不必要的重新渲染

参数一为带有形式参数的 函数:

是对应用变化时组件状态的引用。当然,它不应直接被修改。你应该使用基于 和 构建的新对象来表示变化。例如,假设我们想根据 来增加 state:

updater 函数中接收的 和 都保证为最新。updater 的返回值会与 进行浅合并。

的第二个参数为可选的回调函数,它将在 完成合并并重新渲染组件后执行。通常,我们建议使用 来代替此方式。

的第一个参数除了接受函数外,还可以接受对象类型:


会将传入的对象浅层合并到新的 state 中,例如,调整购物车商品数:

这种形式的 也是异步的,并且在同一周期内会对多个 进行批处理。例如,如果在同一周期内多次设置商品数量增加,则相当于:

后调用的 将覆盖同一周期内先调用 的值,因此商品数仅增加一次。如果后续状态取决于当前状态,我们建议使用 updater 函数的形式代替:

有关更多详细信息,请参阅:

  • State 和生命周期指南
  • 深入学习:何时以及为什么 会批量执行?

默认情况下,当组件的 state 或 props 发生变化时,组件将重新渲染。如果 方法依赖于其他数据,则可以调用 强制让组件重新渲染。

调用 将致使组件调用 方法,此操作会跳过该组件的 。但其子组件会触发正常的生命周期方法,包括 方法。如果标记发生变化,React 仍将只更新 DOM。

通常你应该避免使用 ,尽量在 中使用 和 。

Контролируемые компоненты

В HTML элементы формы, такие как , и , обычно поддерживают собственное состояние и обновляют его в соответствии с пользовательскими входными данными. В React изменяемое состояние обычно хранится в свойстве компонентов и обновляется только с помощью .

Мы можем объединить всё это вместе, сделав состояние React «единственным источником данных (истины)». Затем компонент React, который отрисовывает форму, также контролирует, что происходит в этой форме при последующем вводе данных пользователем. Элемент поля ввода формы, значение которого контролируется React подобным образом, называется «контролируемым компонентом».

Например, если мы хотим, чтобы предыдущий пример выводил на консоль имя при отправке формы, мы можем написать её как контролируемый компонент:

Поскольку атрибут установлен в нашем элементе формы, отображаемое значение всегда будет находится в , что делает состояние React источником данных (истины). Поскольку выполняется при каждом нажатии клавиши, что приводит к обновлению состояния React, то отображаемое значение будет обновляться по мере ввода данных пользователем.

В контролируемом компоненте каждое изменение состояния будет связано с функцией-обработчиком. Это упрощает изменение или проверку входных данных пользователя. Например, если мы хотим, чтобы входные имена записывались заглавными буквами, мы могли бы написать таким образом:

Adding Lifecycle Methods to a Class

In applications with many components, it’s very important to free up resources taken by the components when they are destroyed.

We want to set up a timer whenever the is rendered to the DOM for the first time. This is called “mounting” in React.

We also want to clear that timer whenever the DOM produced by the is removed. This is called “unmounting” in React.

We can declare special methods on the component class to run some code when a component mounts and unmounts:

These methods are called “lifecycle methods”.

The method runs after the component output has been rendered to the DOM. This is a good place to set up a timer:

Note how we save the timer ID right on ().

While is set up by React itself and has a special meaning, you are free to add additional fields to the class manually if you need to store something that doesn’t participate in the data flow (like a timer ID).

We will tear down the timer in the lifecycle method:

Finally, we will implement a method called that the component will run every second.

It will use to schedule updates to the component local state:

Now the clock ticks every second.

Let’s quickly recap what’s going on and the order in which the methods are called:

  1. When is passed to , React calls the constructor of the component. Since needs to display the current time, it initializes with an object including the current time. We will later update this state.
  2. React then calls the component’s method. This is how React learns what should be displayed on the screen. React then updates the DOM to match the ’s render output.
  3. When the output is inserted in the DOM, React calls the lifecycle method. Inside it, the component asks the browser to set up a timer to call the component’s method once a second.
  4. Every second the browser calls the method. Inside it, the component schedules a UI update by calling with an object containing the current time. Thanks to the call, React knows the state has changed, and calls the method again to learn what should be on the screen. This time, in the method will be different, and so the render output will include the updated time. React updates the DOM accordingly.
  5. If the component is ever removed from the DOM, React calls the lifecycle method so the timer is stopped.

Контекст

Контекст React — это глобальное состояние для компонентов.

API контекста React даёт возможность создавать глобальные объекты компонентов, которые будут доступны любому компоненту. Это позволяет обмениваться данными без необходимости передавать свойства по всему дереву DOM.

Как использовать контекст?

Сначала создадим объект контекста:

В документации React установка контекста в компоненте выглядит так:

Однако в CodePen (React 16.4.2) это не сработало. Вместо этого мы воспользуемся КВП, чтобы использовать контекст образом, похожим на тот, что Дэн Абрамов.

Здесь мы оборачиваем компонент в компонент и передаём в контекст в качестве свойства.

Теперь мы можем написать что-то такое:

И у нас будет доступ к из объекта контекста в свойствах.

А как сменить контекст? Это уже немного сложнее, однако мы можем ещё раз использовать КВП и получить что-то такое:

Сначала мы берём исходное состояние контекста — объект, переданный в  — и используем его в качестве состояния компонента-обёртки. Затем мы определяем все методы, которые будем использовать для смены состояния. Наконец, оборачиваем наш компонент в компонент . Мы передаём состояние и функцию в свойство . Теперь они будут в контексте у всех наследников, обёрнутых в компонент .

Собираем всё воедино (КВП опущены для краткости):

Теперь у дочернего компонента есть доступ к глобальному контексту. У него есть возможность изменить значение атрибута в состоянии на .

CodePen со всем кодом по теме контекста.

Компоненты высшего порядка

Возможно, вы уже использовали компоненты высшего порядка (КВП). Например, функция Redux возвращает КВП. Но что из себя представляют эти компоненты?

Из документации React:

Возвращаясь к функции , посмотрим на следующий фрагмент кода:

При вызове мы получаем КВП, который можно использовать для того, чтобы обернуть компонент. Затем мы просто передаём наш компонент в КВП и начинаем использовать возвращаемый им компонент.

КВП позволяют нам абстрагировать общую для компонентов логику в один главный компонент.

КВП можно использовать при авторизации. Код для аутентификации можно написать в каждом компоненте, которому она нужна. В итоге размер кода быстро раздуется до неприличных размеров.

Вот как всё это может выглядеть без КВП:

Тонна повторяющегося кода и запутанная логика!

И вот как код преобразится с использованием КВП:

Вот CodePen со всем кодом.

Глядя на этот код можно понять, что компоненты могут оставаться очень простыми, даже, если будут производить аутентификацию. Компонент содержит всю логику аутентификации. Всё, что он делает, — смотрит на свойство и возвращает или тег в зависимости от присвоенного свойству значения.

Как видите, КВП очень полезны, так как позволяют повторно использовать код. Скоро мы к ним вернёмся.


С этим читают