Написание чистого и удобочитаемого кода необходимо для повышения его качества. Кроме того, чистый код легче тестировать. Нет причин не потратить пять лишних минут на рефакторинг кода, чтобы сделать его более удобным для чтения.
В этой статье рассматриваются шесть лучших практик React 2021 года, чтобы улучшить свой код. Речь пойдет о следующих пунктах:
Когда у вас есть форма с одним полем ввода, вы напишете одну функцию onFirstInputChange для перехвата содержимого поля ввода.
Однако нужно ли писать десять обработчиков событий, если у вас есть форма с десятью полями ввода? Ответ - нет.
Мы можем установить свойство name для поля ввода и обращаться к нему из обработчика событий. Это значение позволяет нам использовать один обработчик ввода для событий onChange.
Вот текущая ситуация при использовании неоптимизированной формы с двумя полями ввода. Нам приходится определять обработчик события onChange для каждого отдельного элемента ввода формы. Этот шаблон создает много повторяющегося кода, который трудно поддерживать.
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
item1: "",
item2: "",
items: "",
errorMsg: ""
};
this.onFirstInputChange = this.onFirstInputChange.bind(this);
this.onSecondInputChange = this.onSecondInputChange.bind(this);
}
onFirstInputChange(event) {
const value = event.target.value;
this.setState({
item1: value
});
}
onSecondInputChange(event) {
const value = event.target.value;
this.setState({
item2: value
});
}
render() {
return (
<div>
<div className="input-section">
{this.state.errorMsg && (
<p className="error-msg">{this.state.errorMsg}</p>
)}
<input
type="text"
name="item1"
placeholder="Enter text"
value={this.state.item1}
onChange={this.onFirstInputChange}
/>
<input
type="text"
name="item2"
placeholder="Enter more text"
value={this.state.item2}
onChange={this.onSecondInputChange}
/>
</div>
</div>
);
}
}
Как вы можете видеть, каждая функция обработчика события обновляет состояние. При работе с несколькими элементами формы код становится очень запутанным, поскольку для каждого события приходится писать новую функцию.
Давайте решим эту ситуацию по-другому, используя поле name. Можно получить доступ к этому значению через свойство event.target.name. Теперь создадим одну функцию, которая будет обрабатывать оба события одновременно. Поэтому удалим обе функции onFirstInputChange и onSecondInputChange.
onInputChange = (event) => {
const name = event.target.name;
const value = event.target.value;
this.setState({
[name]: value
});
};
Легко, верно? Конечно, часто требуется дополнительная проверка данных, которые вы сохраняете в своем состоянии. Используйте оператор switch, чтобы добавить пользовательские правила проверки для каждого отправленного значения.
#2: Избегайте ручного биндинга this
Скорее всего, вы знаете, что React не сохраняет биндинг this при присоединении обработчика к событиям onClick или onChange. Поэтому нам необходимо привязать this вручную. Для чего мы привязываем *this*? Мы хотим привязать this обработчика события к экземпляру компонента, чтобы не потерять контекст, когда мы передаем его в качестве обратного вызова.
Вот классический пример "биндинга", который происходит в конструкторе.
class Button extends Component {
constructor(props) {
super(props);
this.state = { clicked: false };
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.props.setState({ clicked: true });
}
render() {
return <button onClick={this.handleClick}>Click me!</button>;
);
}
Тем не менее, биндинг больше не нужен, поскольку команда create-react-app CLI использует плагин @babel/babel-plugin-transform-class-properties версии >=7 и плагин babel/plugin-proposal-class-properties версии <7.
class Button extends Component {
constructor(props) {
super(props);
this.state = { clicked: false };
}
handleClick = () => this.setState({clicked: true });
render() {
return <button onClick={this.handleClick}>Click me!</button>;
);
}
Это так просто, как только возможно! Вам не нужно беспокоиться о биндинге функций в конструкторе.
#3: Используйте хуки React для обновления состояния
Начиная с версии React 16.8.0, появилась возможность использовать методы состояния и жизненного цикла внутри функциональных компонентов с помощью хуков React. Другими словами, можно писать более читабельный код, который также намного проще поддерживать.
Для этого мы будем применять хук useState. Для тех, кто не знает, что такое хук и зачем его использовать - вот краткое определение из документации React.
this.setState({
errorMsg: "",
items: [item1, item2]
});
Давайте воспользуемся хуком useState. Нужно импортировать этот хук из библиотеки react. Теперь мы можем объявить новые переменные состояния и передать им начальное значение. Используя деструктуризацию, получим переменную для извлечения значения и переменную для установки значения (она является функцией). Давайте посмотрим, как это сделать для приведенного выше примера.
import React, { useState } from "react";
const App = () => {
const [items, setIems] = useState([]);
const [errorMsg, setErrorMsg] = useState("");
};
export default App;
Теперь можно напрямую обращаться к константам items и errorMsg в вашем компоненте.
Далее, можно обновить состояние внутри функции следующим образом:
import React, { useState } from "react";
const App = () => {
const [items, setIems] = useState([]);
const [errorMsg, setErrorMsg] = useState("");
return (
<form>
<button onClick={() => setItems(["item A", "item B"])}>
Set items
</button>
</form>
);
};
export default App;
Вот как можно использовать хуки состояний.
#4: Кэширование операций с большими накладными расходами при помощи useMemo
Мемоизация - это техника оптимизации для хранения результатов затратных операций. Другими словами, сортировка часто является затратной операцией, требующей большого количества обработки. Не хочется выполнять эту затратную функцию для каждого рендера страницы.
Поэтому можно использовать хук useMemo для запоминания результата при передаче тех же параметров в мемоизированную функцию. Хук useMemo принимает функцию и входные параметры для запоминания. React называет это массивом зависимостей. Каждое значение, на которое ссылается функция, также должно появиться в вашем массиве зависимостей.
Вот простой, абстрактный пример. Мы передаем два параметра a и b в затратную функцию. Поскольку функция использует оба параметра, добавляем их в массив зависимостей для нашего хука useMemo.
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
#5: Разделение функций на чистые функции для улучшения качества кода
В соответствии с общепринятой практикой React, вы должны разделить функции, которые не используют ваш компонент. Другими словами, это функция, которая не зависит от какого-либо состояния или хуков React.
Поэтому сортировка является отличным примером функции, которую вы можете извлечь как чистую.
Можно задаться вопросом, почему необходимо использовать функциональное программирование?
function ascSort (a, b) {
return a < b ? -1 : (b > a ? 1 : 0);
}
function descSort (a, b) {
return b < a ? -1 : (a > b ? 1 : 0);
}
#6: Создание пользовательских хуков React
Мы узнали, как использовать хуки React useState и useMemo. Тем не менее, React позволяет вам определять собственные хуки, чтобы извлечь логику и сделать компоненты более читаемыми.
Можно задать пользовательские хуки React, начиная с ключевого слова use, как и все остальные хуки React. Это полезно, когда вы хотите разделить логику между различными функциями. Вместо того чтобы копировать функцию, мы можем определить логику в виде React хука и повторно использовать ее в других функциях.
Вот пример React-компонента, который обновляет состояние, когда размер экрана становится меньше 600 пикселей. Если это происходит, переменная isScreenSmall устанавливается в true. В обратном случае переменная становится false. Для обнаружения изменения размера экрана мы используем событие resize из самого окна.
const LayoutComponent = () => {
const [onSmallScreen, setOnSmallScreen] = useState(false);
useEffect(() => {
checkScreenSize();
window.addEventListener("resize", checkScreenSize);
}, []);
let checkScreenSize = () => {
setOnSmallScreen(window.innerWidth < 768);
};
return (
<div className={`${onSmallScreen ? "small" : "large"}`}>
<h1>Hello World!</h1>
</div>
);
};
Теперь мы хотим использовать ту же логику в другом компоненте, который полагается на переменную isScreenSmall. Вместо того чтобы дублировать код, давайте превратим этот пример в пользовательский хук React.
import { useState, useEffect } from "react";
const useSize = () => {
const [isScreenSmall, setIsScreenSmall] = useState(false);
let checkScreenSize = () => {
setIsScreenSmall(window.innerWidth < 600);
};
useEffect(() => {
checkScreenSize();
window.addEventListener("resize", checkScreenSize);
return () => window.removeEventListener("resize", checkScreenSize);
}, []);
return isScreenSmall;
};
export default useSize;
Мы можем создать пользовательский хук React, обернув логику в функцию use. В этом примере мы назвали пользовательский хук React useSize. Теперь можно импортировать хук useSize в любое место, где он нам понадобится.
import React from 'react'
import useSize from './useSize.js'
const LayoutComponent = () => {
const onSmallScreen = useSize();
return (
<div className={`${onSmallScreen ? "small" : "large"}`}>
<h1>Hello World!</h1>
</div>
);
}
Бонусный совет: Мониторинг фронтенда
Мониторинг фронтенда является обязательным, если вы хотите понять, что делают пользователи и как ваше приложение реагирует на эти запросы. OpenReplay - это инструмент мониторинга фронтенда, который воспроизводит все действия ваших пользователей и показывает, как ведет себя ваше веб-приложение при каждой проблеме. Он позволяет воспроизводить проблемы, агрегировать ошибки JS и отслеживать производительность вашего веб-приложения.
Начните отслеживать работу вашего веб-приложения бесплатно.
Вот и все! Эта статья научила вас шести способам улучшения читабельности и качества кода.
В этой статье рассматриваются шесть лучших практик React 2021 года, чтобы улучшить свой код. Речь пойдет о следующих пунктах:
- Используйте event.target.name для обработчиков событий.
- Как избежать ручного биндинга обработчиков событий к this?
- Используйте хуки React для обновления состояния.
- Кэширование затратных операций с useMemo.
- Разделяйте функции на отдельные элементы для улучшения качества кода.
- Как создавать пользовательские хуки в React?
Когда у вас есть форма с одним полем ввода, вы напишете одну функцию onFirstInputChange для перехвата содержимого поля ввода.
Однако нужно ли писать десять обработчиков событий, если у вас есть форма с десятью полями ввода? Ответ - нет.
Мы можем установить свойство name для поля ввода и обращаться к нему из обработчика событий. Это значение позволяет нам использовать один обработчик ввода для событий onChange.
Вот текущая ситуация при использовании неоптимизированной формы с двумя полями ввода. Нам приходится определять обработчик события onChange для каждого отдельного элемента ввода формы. Этот шаблон создает много повторяющегося кода, который трудно поддерживать.
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
item1: "",
item2: "",
items: "",
errorMsg: ""
};
this.onFirstInputChange = this.onFirstInputChange.bind(this);
this.onSecondInputChange = this.onSecondInputChange.bind(this);
}
onFirstInputChange(event) {
const value = event.target.value;
this.setState({
item1: value
});
}
onSecondInputChange(event) {
const value = event.target.value;
this.setState({
item2: value
});
}
render() {
return (
<div>
<div className="input-section">
{this.state.errorMsg && (
<p className="error-msg">{this.state.errorMsg}</p>
)}
<input
type="text"
name="item1"
placeholder="Enter text"
value={this.state.item1}
onChange={this.onFirstInputChange}
/>
<input
type="text"
name="item2"
placeholder="Enter more text"
value={this.state.item2}
onChange={this.onSecondInputChange}
/>
</div>
</div>
);
}
}
Как вы можете видеть, каждая функция обработчика события обновляет состояние. При работе с несколькими элементами формы код становится очень запутанным, поскольку для каждого события приходится писать новую функцию.
Давайте решим эту ситуацию по-другому, используя поле name. Можно получить доступ к этому значению через свойство event.target.name. Теперь создадим одну функцию, которая будет обрабатывать оба события одновременно. Поэтому удалим обе функции onFirstInputChange и onSecondInputChange.
onInputChange = (event) => {
const name = event.target.name;
const value = event.target.value;
this.setState({
[name]: value
});
};
Легко, верно? Конечно, часто требуется дополнительная проверка данных, которые вы сохраняете в своем состоянии. Используйте оператор switch, чтобы добавить пользовательские правила проверки для каждого отправленного значения.
#2: Избегайте ручного биндинга this
Скорее всего, вы знаете, что React не сохраняет биндинг this при присоединении обработчика к событиям onClick или onChange. Поэтому нам необходимо привязать this вручную. Для чего мы привязываем *this*? Мы хотим привязать this обработчика события к экземпляру компонента, чтобы не потерять контекст, когда мы передаем его в качестве обратного вызова.
Вот классический пример "биндинга", который происходит в конструкторе.
class Button extends Component {
constructor(props) {
super(props);
this.state = { clicked: false };
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.props.setState({ clicked: true });
}
render() {
return <button onClick={this.handleClick}>Click me!</button>;
);
}
Тем не менее, биндинг больше не нужен, поскольку команда create-react-app CLI использует плагин @babel/babel-plugin-transform-class-properties версии >=7 и плагин babel/plugin-proposal-class-properties версии <7.
Ниже приведен пример синтаксиса стрелочной функции. Здесь нам не нужно писать дополнительный код в конструкторе, чтобы связать this.Примечание: Вам необходимо изменить синтаксис обработчика событий на синтаксис стрелочной функции.
class Button extends Component {
constructor(props) {
super(props);
this.state = { clicked: false };
}
handleClick = () => this.setState({clicked: true });
render() {
return <button onClick={this.handleClick}>Click me!</button>;
);
}
Это так просто, как только возможно! Вам не нужно беспокоиться о биндинге функций в конструкторе.
#3: Используйте хуки React для обновления состояния
Начиная с версии React 16.8.0, появилась возможность использовать методы состояния и жизненного цикла внутри функциональных компонентов с помощью хуков React. Другими словами, можно писать более читабельный код, который также намного проще поддерживать.
Для этого мы будем применять хук useState. Для тех, кто не знает, что такое хук и зачем его использовать - вот краткое определение из документации React.
Сначала давайте рассмотрим, как мы обновляем состояние с помощью хука setState.Что такое хук? Хук - это специальная функция, которая позволяет вам "подключаться" к фичам React. Например, useState - это хук, который позволяет добавлять состояние React в компоненты функции.
Когда я могу использовать хук? Если вы пишете функциональный компонент и понимаете, что вам нужно добавить в него состояние, раньше вам приходилось преобразовывать его в класс. Теперь можно использовать хук внутри существующего функционального компонента.
this.setState({
errorMsg: "",
items: [item1, item2]
});
Давайте воспользуемся хуком useState. Нужно импортировать этот хук из библиотеки react. Теперь мы можем объявить новые переменные состояния и передать им начальное значение. Используя деструктуризацию, получим переменную для извлечения значения и переменную для установки значения (она является функцией). Давайте посмотрим, как это сделать для приведенного выше примера.
import React, { useState } from "react";
const App = () => {
const [items, setIems] = useState([]);
const [errorMsg, setErrorMsg] = useState("");
};
export default App;
Теперь можно напрямую обращаться к константам items и errorMsg в вашем компоненте.
Далее, можно обновить состояние внутри функции следующим образом:
import React, { useState } from "react";
const App = () => {
const [items, setIems] = useState([]);
const [errorMsg, setErrorMsg] = useState("");
return (
<form>
<button onClick={() => setItems(["item A", "item B"])}>
Set items
</button>
</form>
);
};
export default App;
Вот как можно использовать хуки состояний.
#4: Кэширование операций с большими накладными расходами при помощи useMemo
Мемоизация - это техника оптимизации для хранения результатов затратных операций. Другими словами, сортировка часто является затратной операцией, требующей большого количества обработки. Не хочется выполнять эту затратную функцию для каждого рендера страницы.
Поэтому можно использовать хук useMemo для запоминания результата при передаче тех же параметров в мемоизированную функцию. Хук useMemo принимает функцию и входные параметры для запоминания. React называет это массивом зависимостей. Каждое значение, на которое ссылается функция, также должно появиться в вашем массиве зависимостей.
Вот простой, абстрактный пример. Мы передаем два параметра a и b в затратную функцию. Поскольку функция использует оба параметра, добавляем их в массив зависимостей для нашего хука useMemo.
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
#5: Разделение функций на чистые функции для улучшения качества кода
В соответствии с общепринятой практикой React, вы должны разделить функции, которые не используют ваш компонент. Другими словами, это функция, которая не зависит от какого-либо состояния или хуков React.
Поэтому сортировка является отличным примером функции, которую вы можете извлечь как чистую.
Можно задаться вопросом, почему необходимо использовать функциональное программирование?
Теперь давайте применим эту концепцию к компонентам React. Вот функция, которая может находиться как внутри компонента React, так и снаружи. Обе они являются функциями сравнения, которые вы можете передать затратной функции сортировки, принимающей два входных параметра. Поскольку здесь нет взаимодействия с состоянием, можно извлечь обе функции в виде чистых. Это позволяет нам поместить чистые функции в отдельный файл и при необходимости импортировать их в несколько мест.Функциональное программирование - это процесс создания программного обеспечения путем компоновки чистых функций, избегая общего для всех состояния, мутируемых данных и побочных эффектов. Чистые функции лучше читаются и легче тестируются. Поэтому они улучшают качество кода. - freeCodeCamp
function ascSort (a, b) {
return a < b ? -1 : (b > a ? 1 : 0);
}
function descSort (a, b) {
return b < a ? -1 : (a > b ? 1 : 0);
}
#6: Создание пользовательских хуков React
Мы узнали, как использовать хуки React useState и useMemo. Тем не менее, React позволяет вам определять собственные хуки, чтобы извлечь логику и сделать компоненты более читаемыми.
Можно задать пользовательские хуки React, начиная с ключевого слова use, как и все остальные хуки React. Это полезно, когда вы хотите разделить логику между различными функциями. Вместо того чтобы копировать функцию, мы можем определить логику в виде React хука и повторно использовать ее в других функциях.
Вот пример React-компонента, который обновляет состояние, когда размер экрана становится меньше 600 пикселей. Если это происходит, переменная isScreenSmall устанавливается в true. В обратном случае переменная становится false. Для обнаружения изменения размера экрана мы используем событие resize из самого окна.
const LayoutComponent = () => {
const [onSmallScreen, setOnSmallScreen] = useState(false);
useEffect(() => {
checkScreenSize();
window.addEventListener("resize", checkScreenSize);
}, []);
let checkScreenSize = () => {
setOnSmallScreen(window.innerWidth < 768);
};
return (
<div className={`${onSmallScreen ? "small" : "large"}`}>
<h1>Hello World!</h1>
</div>
);
};
Теперь мы хотим использовать ту же логику в другом компоненте, который полагается на переменную isScreenSmall. Вместо того чтобы дублировать код, давайте превратим этот пример в пользовательский хук React.
import { useState, useEffect } from "react";
const useSize = () => {
const [isScreenSmall, setIsScreenSmall] = useState(false);
let checkScreenSize = () => {
setIsScreenSmall(window.innerWidth < 600);
};
useEffect(() => {
checkScreenSize();
window.addEventListener("resize", checkScreenSize);
return () => window.removeEventListener("resize", checkScreenSize);
}, []);
return isScreenSmall;
};
export default useSize;
Мы можем создать пользовательский хук React, обернув логику в функцию use. В этом примере мы назвали пользовательский хук React useSize. Теперь можно импортировать хук useSize в любое место, где он нам понадобится.
Вот как теперь выглядит наш компонент. Код стал намного чище!В пользовательских хуках React нет ничего нового. Вы оборачиваете логику функцией и даете ей имя, начинающееся с use. Она действует как обычная функция. Однако, следуя правилу начинаться с "use", вы сообщаете всем, кто импортирует ее, что это хук. Более того, поскольку это хук, вы должны структурировать его таким образом, чтобы он соответствовал правилам хуков.
import React from 'react'
import useSize from './useSize.js'
const LayoutComponent = () => {
const onSmallScreen = useSize();
return (
<div className={`${onSmallScreen ? "small" : "large"}`}>
<h1>Hello World!</h1>
</div>
);
}
Бонусный совет: Мониторинг фронтенда
Мониторинг фронтенда является обязательным, если вы хотите понять, что делают пользователи и как ваше приложение реагирует на эти запросы. OpenReplay - это инструмент мониторинга фронтенда, который воспроизводит все действия ваших пользователей и показывает, как ведет себя ваше веб-приложение при каждой проблеме. Он позволяет воспроизводить проблемы, агрегировать ошибки JS и отслеживать производительность вашего веб-приложения.
Начните отслеживать работу вашего веб-приложения бесплатно.
Вот и все! Эта статья научила вас шести способам улучшения читабельности и качества кода.
6 лучших практик React в 2021 году
Написание чистого и удобочитаемого кода необходимо для повышения его качества. Кроме того, чистый код легче тестировать. Нет причин не потратить пять лишних минут на рефакторинг кода, чтобы сделать...
habr.com