Как использовать фрагменты React
год назад·1 мин. на чтение
В этой статье рассмотрим использование фрагментов в приложениях React.
Что такое React Fragment?
React Fragment - это компонент React, который помогает нам возвращать несколько дочерних элементов без использования дополнительных DOM узлов. Если мы хотим вернуть группу элементов, то нужно обернуть их в общий тег. React компонент должен возвращать только один элемент, иначе будет ошибка. Следующий пример не будет работать, т.к. компонент возвращает несколько элементов -h1
и p
.
Фрагменты React представлены в версии 16. Давайте посмотрим на несколько примеров.import React from 'react'; function Welcome(props){ return ( <h1>Welcome to reactgo.com</h1> <p>Some dummy content</p> ) }
Без фрагментов React
Теперь мы заменяем код компонента приветствия с помощью фрагментов.import React from 'react'; function Welcome(props){ return ( <div> <h1>Welcome to reactgo.com</h1> <p>Some dummy content</p> </div> ) }
С помощью React Fragments
Используя фрагменты, мы перестали создавать дополнительный элементimport React,{Fragment} from 'react'; function Welcome(props){ return ( <Fragment> <h1>Welcome to reactgo.com</h1> <p>Some dummy content</p> </Fragment> ) }
div
в компоненте Welcome
.
Короткий синтаксис фрагментов
Существует также краткий синтаксис для фрагментов.Этот синтаксис использует пустые теги для объявления фрагментов react.import React from 'react'; function Welcome(props){ return ( <> <h1>Welcome to reactgo.com</h1> <p>Some dummy content</p> </> ) }
Еще несколько примеров
Использование фрагментов при возврате группы дочерних компонентов.function Button(){ return <button>Click</button> } function Name(){ return <h1>Hi react</h1> } function Post(){ return ( <div> <h1>Heading...</h1> <p>post content</p> </div> ) } function App(){ return ( <> <Post/> <Name/> <Button/> </> ) }
11 ошибок, которых следует избегать при создании React приложений
2 года назад·7 мин. на чтение
Некоторые распространенные ошибки в разработке React приложений, которых следует избегать.
Поскольку React становится все более и более популярным, все больше и больше React разработчиков сталкиваются с различными проблемами в процессе разработки.
В этой статье, мы обобщим некоторые распространенные ошибки в разработке React приложений, чтобы помочь вам их избежать.
Если вы только начинаете использовать React, рекомендуется внимательно ознакомиться с этой статьей. Если вы уже используете React для разработки проектов, также рекомендуется проверить и заполнить пробелы.
Прочитав эту статью, вы узнаете, как избежать эти 11 ошибок React:
Ошибка: При рендеринге списка не используется
Проблема
Когда мы впервые изучали React, мы отображали список следующим образом:
Ошибка: Использование состояния сразу после выполнения
Проблема
Когда мы изменяем данные через
Ошибка: Появление бесконечного цикла при использовании
Проблема
Когда мы напрямую вызываем метод
Приведем 4 случая использования
Ошибка: Отсутствие очистки побочных эффектов в
Проблема
В классовых компонентах мы используем метод жизненного цикла
- При рендеринге списка не используется
key
- Изменение значения состояния прямым присваиванием
- Привязка значения состояния непосредственно к свойству value инпута
- Использование состояния сразу после выполнения
setState
- Появление бесконечного цикла при использовании
useState
+useEffect
- Отсутствие очистки побочных эффектов в
useEffect
- Неправильное использование логических операторов
- Тип пропсов компонента не типизирован
- Передача строк в качестве значений компонентам
- Имя компонента не начинается с заглавной буквы
- Неверная привязка события к элементу
Ошибка: При рендеринге списка не используется key
Проблема
Когда мы впервые изучали React, мы отображали список следующим образом:
После рендеринга консоль выдаст предупреждение, что для элементов списка необходимо указать ключ. Решение Вам просто нужно последовать этой подсказке и добавитьconst items = [ { id: 1, value: 'item1' }, { id: 2, value: 'item2' }, { id: 3, value: 'item3' }, { id: 4, value: 'item4' }, { id: 5, value: 'item5' } ]; const listItems = items.map((item) => { return <li>{item.value}</li> });
key
к каждому элементу:
const items = [ { id: 1, value: ‘item1’ }, { id: 2, value: ‘item2’ }, { id: 3, value: ‘item3’ }, { id: 4, value: ‘item4’ }, { id: 5, value: ‘item5’ } ]; const listItems = items.map((item) => { return <li key={item.id}>{item.value}</li> });
key
помогает React определить, какие элементы были изменены, например, добавлены или удалены. Поэтому нам нужно установить уникальное значение ключа для каждого элемента в массиве.
Для значения ключа лучше всего установить уникальное значение. В приведенном выше примере используется id
. Можно использовать индекс массива, но такой подход не рекомендуется.
Уникальный ключ помогает React следить за изменениями списка - какой элемент удалился или переместился.
Ошибка: Изменение значения состояния прямым присваиванием
Проблема В React нельзя назначать состояние и изменять напрямую, иначе это вызовет проблемы.В этот момент будет выдано предупреждение не изменять состояние напрямую, а использовать// классовый компонент handleChange = () => { this.state.name = "John"; };
setState()
.
Решение
Классовые компоненты могут быть изменены с помощью setState()
, а функциональные компоненты могут быть изменены с помощью useState()
:
// Классовые компоненты: используйте setState() this.setState({ name: "John" }); // Функциональные компоненты:используйте useState() const [name, setName] = useState(""); setName("John");
Ошибка: Привязка значения состояния непосредственно к свойству value инпута
Проблема Когда мы напрямую привязываем значение состояния к свойствуvalue
инпута, мы обнаружим, что независимо от того, что мы вводим в поле ввода, содержимое поля ввода не изменится.
Это связано с тем, что мы используем переменную состояния в качестве значения по умолчанию для присвоения значенияexport default function App() { const [count, setCount] = useState(0); return <input type="text" value={count} />; }
<input>
, а состояние в функциональном компоненте может быть изменено только функцией set*
, возвращаемым useState
. Таким образом, решение также очень простое, просто используйте функцию set*
при изменении. Подробнее о том как работать с инпутом в React можно прочитать в этой статье.
Решение
Просто привяжите событие onChange
к <input>
и измените его, вызвав setCount
:
export default function App() { const [count, setCount] = useState(0); const handleChange= (event) => setCount(event.target.value); return <input type="text" value={count} onChange={handleChange} />; }
Ошибка: Использование состояния сразу после выполнения setState
Проблема
Когда мы изменяем данные через setState()
и сразу же хотим получить новые данные, возникнет ситуация, что возвращаются старые данные:
Это связано с тем, что// Классовые компоненты // инициализация состояния this.state = { name: "John" }; // обновление состояния this.setState({ name: "Hello, John!" }); console.log(this.state.name); // => John
setState()
является асинхронным. Когда setState()
выполняется, реальная операция обновления будет помещена в асинхронную очередь для выполнения, а код, который будет выполняться следующим (т.е. console.log
в примере), выполняется синхронно, поэтому выводимое в консоль состояние не является последним значением.
Решение
Просто передайте последующую операцию, которая будет выполняться как функция, в качестве второго параметра setState()
, эта функция обратного вызова будет выполнена после завершения обновления.
Теперь обновленное значение выводится правильно.this.setState({ name: "Hello, John!" }, () => { console.log(this.state.name); // => Hello, John! });
Ошибка: Появление бесконечного цикла при использовании useState
+ useEffect
Проблема
Когда мы напрямую вызываем метод set*()
, возвращаемый useState()
внутри useEffect()
, и не устанавливаем второй параметр в useEffect()
, мы столкнемся с бесконечным циклом:
После этого можно увидеть, что данные на странице обновляются, и функцияexport default function App() { const [count, setCount] = useState(0); useEffect(() => { setCount(count + 1); }); return <div className="App">{count}</div>; }
useEffect()
вызывается бесконечно, входя в состояние бесконечного цикла.
Решение
Это распространенная проблема неправильного использования useEffect()
. useEffect()
можно рассматривать как комбинацию трех функций жизненного цикла: componentDidMount
, componentDidUpdate
и componentWillUnmount
в классовых компонентах. useEffect(effect, deps)
принимает 2 аргумента:
effect
функция, которая должна выполниться (побочный эффект)deps
массив зависимостей
deps
выполняется функция эффекта. Чтобы изменить метод, вам нужно всего лишь передать []
в качестве второго аргумента useEffect()
:
export default function App() { const [count, setCount] = useState(0); useEffect(() => { setCount(count + 1); }, []); return <div className="App">{count}</div>; }
useEffect
:
- Если второй параметр не передан: при обновлении любого состояния будет запущена функция эффекта
useEffect
.
useEffect(() => { setCount(count + 1); });
- Если второй параметр - это пустой массив: функция эффекта
useEffect
срабатывает только при монтировании и размонтировании.
useEffect(() => { setCount(count + 1); }, []);
- Если второй параметр представляет собой массив с одним значением: функция эффекта
useEffect
будет запускаться только при изменении значения.
useEffect(() => { setCount(count + 1); }, [name]);
- Если второй параметр представляет собой массив c несколькими значениями: функция эффекта
useEffect
будет запускаться при изменении хотя бы одного из значений из списка зависимостей.
useEffect(() => { setCount(count + 1); }, [name, age]);
Ошибка: Отсутствие очистки побочных эффектов в useEffect
Проблема
В классовых компонентах мы используем метод жизненного цикла componentWillUnmount()
для очистки некоторых побочных эффектов, таких как таймеры, слушатели событий и т. д.
Решение
Из функции эффекта useEffect()
может быть возвращена функция очистки, которая аналогична роли метода жизненного цикла componentWillUnmount()
:
useEffect(() => { // ... return () => clearInterval(id); }, [name, age]);
Ошибка: Неправильное использование логических операторов
Проблема В синтаксисе JSX/TSX мы часто используем логические значения для управления отображаемыми элементами, и во многих случаях мы используем оператор&&
для обработки этой логики:
Мы думаем, что в это время страница будет отображать пустой контент, но на самом деле на ней отобразитсяconst count = 0; const Comp = () => count && <h1>Chris1993</h1>;
0
.
Решение
Причина в том, что ложное выражение приводит к тому, что элементы после &&
пропускаются, и будет возвращено значение ложного выражения. Поэтому нужно стараться написать условие оценки как можно более полным, не полагаясь на истинное и ложное логическое значение JavaScript для сравнения:
Теперь страница будет отображать пустой контент, как и ожидается.const count = 0; const Comp = () => count > 0 && <h1>Chris1993</h1>;
Ошибка: Типы просов компонента не типизированы
Проблема Если компоненты, разработанные разными членами команды, не имеют четко определенных типов для просов, то для коллег будет не очевидно, как использовать компоненты, например:Решениеconst UserInfo = (props) => { return ( <div> {props.name} : {props.age} </div> ); };
- Определить типы пропсов компонента, используя TypeScript.
// Классовые компоненты interface AppProps { value: string; } interface AppState { count: number; } class App extends React.Component<AppProps, AppStore> { // ... } // Функциональные компоненты interface AppProps { value?: string; } const App: React.FC<AppProps> = ({ value = "", children }) => { //... };
- Без использования TypeScript типы пропсов могут быть определены с помощью
propTypes
.
const UserInfo = (props) => { return ( <div> {props.name} : {props.age} </div> ); }; UserInfo.propTypes = { name: PropTypes.string.isRequired, age: PropTypes.number.isRequired, };
Ошибка: Передача строк в качестве значений компонентам
Проблема Так как React имеет шаблонный синтаксис, очень похожий на HTML, часто бывает так, что числа передаются напрямую компонентам в пропсы, что приводит к неожиданному результату:Сравнение<MyComp count="99"></MyComp>
props.count === 99
в компоненте MyComp
вернет false
.
Решение
Правильный способ должен заключаться в использовании фигурных скобок для передачи пропсов:
Передача строковых просов будет выглядеть следующим образом:<MyComp count={99}></MyComp>
<MyComp count={"99"}></MyComp>
Ошибка: Имя компонента не начинается с заглавной буквы
Проблема Начинающие разработчики часто забывают называть свои компоненты с заглавной буквы. Компоненты, начинающиеся со строчной буквы в JSX/TSX, компилируются в элементы HTML, такие как<div />
для тегов HTML.
Решение Просто измените первую букву на заглавную:class myComponent extends React.component {}
class MyComponent extends React.component {}
Ошибка: Неверная привязка события к элементу в классовых компонентах
ПроблемаПри нажатии на кнопкуimport { Component } from "react"; export default class HelloComponent extends Component { constructor() { super(); this.state = { name: "John", }; } update() { this.setState({ name: "Hello John!" }); } render() { return ( <div> <button onClick={this.update}>update</button> </div> ); } }
update
консоль сообщит об ошибке, что невозможно прочитать свойства undefined
(чтение setState
)
Решение
Это происходит потому, что this
не привязан к тому контексту, который мы ожидаем. Есть несколько решений:
- Привязать контекст в конструкторе при помощи метода
bind
constructor() { super(); this.state = { name: "John" }; this.update = this.update.bind(this); }
- Использовать стрелочные функции
update = () => { this.setState({ name: "Hello John!" }); };
- Привязать прямо в функции рендеринга
<button onClick={this.update.bind(this)}>update</button>
- Использовать стрелочные функции в функции рендеринга (не рекомендуется, т.к. это создает новую функцию каждый раз при рендеринге компонента, что влияет на производительность)
<button onClick={() => this.update()}>update</button>