Что такое Батчинг в ReactJS
месяц назад·4 мин. на чтение
В данной статье мы рассмотрим понятие "батчинг" в ReactJS и посмотрим, как он может повысить производительность и улучшить пользовательский опыт веб-приложений.
React 18 включает в себя улучшения производительности «из коробки» путем использования более частых операций пакетной обработки по умолчанию, что устраняет необходимость вручную объединять обновления в коде приложения или библиотеки.
Это функциональность, о которой большинству пользователей можно не думать. Однако она может быть актуальна для преподавателей и разработчиков библиотек.
Что такое пакетная обработка (batching)?
Пакетная обработка (batching) - это когда React группирует несколько обновлений состояния в одно перерисовку для повышения производительности. Например, если у вас есть два обновления состояния внутри одного события клика, React всегда собирает их в одну перерисовку. Если вы выполните следующий код, вы увидите, что каждый раз, когда вы кликаете, React выполняет только одну перерисовку, хотя вы устанавливаете состояние дважды:Это отлично для производительности, потому что это позволяет избежать ненужных повторных рендеров. Это также предотвращает отображение компонента в "незаконченном" состоянии, где была обновлена только одна переменная состояния, что может вызвать ошибки. Это может напомнить вам о том, как официант ресторана не бежит на кухню, когда вы выбираете первое блюдо, а ждет, пока вы закончите заказ. Однако, React не всегда одинаково объединял обновления. Например, если вам нужно загрузить данные, а затем обновить состояние в указанном вышеfunction App() { const [count, setCount] = useState(0); const [flag, setFlag] = useState(false); function handleClick() { setCount(c => c + 1); // Пока не происходит повторное отображение setFlag(f => !f); // Пока не происходит повторное отображение // React перерисует только один раз в конце (это пакетная обработка!) } return ( <div> <button onClick={handleClick}>Next</button> <h1 style={{ color: flag ? "blue" : "black" }}>{count}</h1> </div> ); }
handleClick
, то React не будет объединять обновления и будет выполнять два независимых обновления.
Это происходит потому, что React раньше выполнял пакетную обработку только во время события браузера (например, нажатия кнопки), а здесь мы обновляем состояние после обработки события (в callback-функции fetch
):
До React 18 мы объединяли обновления только в обработчиках событий React. Обновления внутриfunction App() { const [count, setCount] = useState(0); const [flag, setFlag] = useState(false); function handleClick() { fetchSomething().then(() => { // React 17 и более ранние НЕ объединяют эти обновления, потому что // они запускаются ПОСЛЕ события в callback-функции, а не ВО ВРЕМЯ события setCount(c => c + 1); // Вызывает повторное отображение setFlag(f => !f); // Вызывает повторный рендеринг }); } return ( <div> <button onClick={handleClick}>Next</button> <h1 style={{ color: flag ? "blue" : "black" }}>{count}</h1> </div> ); }
Promise
, setTimeout
, нативных обработчиков событий или любых других событий по умолчанию не объединялись в React.
Что такое автоматическая пакетная обработка?
Начиная с React 18 с использованиемcreateRoot
, все обновления будут автоматически объединяться, независимо от их происхождения.
Это означает, что обновления внутри таймеров, Promise
, нативных обработчиков событий или любых других событий будут объединяться так же, как и обновления внутри событий React. Мы ожидаем, что это приведет к уменьшению работы по отрисовке и, следовательно, к лучшей производительности в ваших приложениях:
Примечание: Ожидается, что вы начнете использоватьfunction App() { const [count, setCount] = useState(0); const [flag, setFlag] = useState(false); function handleClick() { fetchSomething().then(() => { // React 18 и позднее ОБЪЕДИНЯЕТ эти обновления: setCount(c => c + 1); setFlag(f => !f); // React перерисует только один раз в конце (это пакетная обработка!) }); } return ( <div> <button onClick={handleClick}>Next</button> <h1 style={{ color: flag ? "blue" : "black" }}>{count}</h1> </div> ); }
createRoot
вместе с переходом на React 18.
React будет автоматически объединять обновления, независимо от того, где они происходят, так что это:
Примечание: React объединяет обновления только тогда, когда это обычно безопасно. Например, React гарантирует, что для каждого события, инициированного пользователем, такого как клик или нажатие клавиши, DOM полностью обновляется перед следующим событием. Это гарантирует, например, что форма, которая отключается при отправке, не может быть отправлена дважды.function handleClick() { setCount(c => c + 1); setFlag(f => !f); // React перерисует только один раз в конце (это пакетная обработка!) } и равносильно этому: setTimeout(() => { setCount(c => c + 1); setFlag(f => !f); // React перерисует только один раз в конце (это пакетная обработка!) }, 1000); и равносильно этому: fetch(/*...*/).then(() => { setCount(c => c + 1); setFlag(f => !f); // React перерисует только один раз в конце (это пакетная обработка!) }) и равносильно этому: elm.addEventListener('click', () => { setCount(c => c + 1); setFlag(f => !f); // React перерисует только один раз в конце (это пакетная обработка!) });
Что, если я не хочу использовать пакетную обработку?
Обычно пакетная обработка безопасна, но некоторый код может зависеть от считывания чего-либо из DOM сразу после изменения состояния. Для таких случаев вы можете использоватьReactDOM.flushSync()
, чтобы отключить пакетную обработку:
Подробнее в оригинальной статье на GitHubimport { flushSync } from 'react-dom'; // Обратите внимание: react-dom, а не react function handleClick() { flushSync(() => { setCounter(c => c + 1); }); // React уже обновил DOM flushSync(() => { setFlag(f => !f); }); // React уже обновил DOM }
Обработка форм в React с помощью хуков
2 года назад·3 мин. на чтение
В этой статье рассмотрим, как обрабатывать формы в приложениях react с помощью хуков.
Формы
Формы позволяют нам принимать данные от пользователей и отправлять их на сервер для обработки. Это различные типы форм, такие как «Вход», «Регистрация» и т.д. В HTML5 есть элементы формы, такие какinput
, textarea
, select
, они поддерживают собственное внутреннее состояние в DOM, но в React мы поддерживаем состояние элементов формы внутри компонента, чтобы мы могли иметь полный контроль над элементами формы.
Что такое обработка форм
Обработка форм означает, как мы обрабатываем данные формы, когда пользователь изменяет значение или отправляет форму. Давайте посмотрим на пример того, как мы обрабатываем данные инпута с помощью хуков React.В приведенном выше коде мы установили для атрибутаimport React,{useState} from 'react'; function Form() { const [name,setName] = useState(''); function handleNameChange(e){ setName(e.target.value) } function handleSubmit(e) { e.preventDefault() // останавливаем перезагрузку страницы по умолчанию console.log(name); } return ( <form onSubmit={handleSubmit}> <input placeholder="Name" value={name} onChange={handleNameChange}/> <button>Submit</button> </form> ) }
value
элемента input
свойство name
, а метод обработчика событий onChange
- handleNameChange
- запускается каждый раз, когда мы вводим некоторые данные в элемент input
, и он обновляет свойство name
с помощью метода setName
, так что мы продолжаем синхронизировать значение с состоянием react.
handleSubmit
используется для отправки формы.
Элемент select
<select>
помогает нам создать выпадающий список. Давайте посмотрим на пример того, как создать выпадающий список и обрабатывать данные.
Здесь мы создали выпадающий список фреймворков в элементеimport React,{useState} from 'react'; function FormSelect() { // начальное значение состояния - строка 'react' const [framework, setFramework] = useState('react'); function handleChange(e){ setFramework(e.target.value); }; function handleSubmit(e){ e.preventDefault(); console.log(framework); }; return ( <form onSubmit={handleSubmit}> <h2>Choose your framework</h2> <select onChange={handleChange} value={framework}> <option value="react">React</option> <option value="angular">Angular</option> <option value="vue">Vue</option> </select> <button type="submit">Submit</button> </form> ); }
<select>
мы установили атрибут value
для свойства framework
и добавили обработчик событий onChange
.
Вложенные элементы <option>
содержат атрибут value
, который содержит данные, так что всякий раз, когда мы выбираем конкретный параметр, вызывается метод handleChange
и изменяет значение свойства framework
значением атрибута <option>
.
Вы видели, что элемент select
также следует аналогичному шаблону, как и элемент input
, так почему бы нам не создать пользовательский хук и повторно использовать его в каждом элементе формы?
Создание пользовательских хуков для обработки формы
Здесь мы создали пользовательский хук под названиемimport React, {useState} from 'react'; function useInput(initialValue) { const [value,setValue] = useState(initialValue); function handleChange(e) { setValue(e.target.value); } return [value,handleChange]; }
useInput
, давайте его применим.
Использование пользовательского хука useInput()
Теперь наш компонентfunction LoginForm(){ const [email, setEmail] = useInput(''); const [password, setPassword] = useInput(''); function handleSubmit(e){ e.preventDefault(); console.log(email,password) } return ( <form onSubmit={handleSubmit}> <input placeholder="Email" type="email" value={email} onChange={setEmail}/> <input placeholder="password" type="password" value={password} onChange={setPassword}/> <button>Submit</button> </form> ) }
LoginForm
выглядит намного чище с помощью пользовательского хука useInput()
. Точно так же мы можем использовать наш хук useInput
с другими элементами формы.
Пример с Radio button
function RadioButtons() { const [data] = useState({male:"male",female:"female",other:"other"}) const [gender, setGender] = useInput(""); function handleSubmit(e) { e.preventDefault(); console.log(gender); } return ( <form onSubmit={handleSubmit}> <h1>Select Your Gender</h1> <div> <input type="radio" id={data.male} value={data.male} checked={data.male === gender} onChange={setGender}/> <label htmlFor={data.male}>Male</label> </div> <div> <input type="radio" id={data.female} value={data.female} checked={data.female === gender} onChange={setGender}/> <label htmlFor={data.female}>Female</label> </div> <div> <input type="radio" id={data.other} value={data.other} checked={data.other === gender} onChange={setGender}/> <label htmlFor={data.other}>Other</label> </div> <button>submit</button> </form> ) }
Пример элемента Textarea
function Comments() { const [comment, setComment] = useInput(""); function handleSubmit(e) { e.preventDefault(); console.log(comment); } return( <form onSubmit={handleSubmit}> <textarea value={comment} onChange={setComment}/> <button>submit</button> </form> ) }