React – фронтенд-библиотека для создания веб-приложений.
Концепция компонентов – одна из самых важных в React. Компоненты в React просто создавать и переиспользовать, вокруг компонентов строится вся разработка.
Давайте разберемся с ними подробнее.
Что такое React-компоненты?
Компоненты в React – независимые единицы, из которых складывается приложение. Вы можете думать о компонентах, как о строительных блоках, из которых потом собирается дом – React-приложение. При разработке на React вы будете использовать компоненты постоянно – без их создания написать приложение не получится (как не получится построить дом без кирпичей). Иерархически собранные компоненты и представляют собой React-приложение.
const myFirstComponent = () => <h1>Yes! I wrote a component</h1>
Код выше описывает создание очень простого функционального компонента, который показывает заголовок h1. Важно понимать, возвращаемая компонентом разметка – не HTML. Это JSX. Подробнее о том, что такое JSX, можно прочитать здесь.
Типы компонентов
В React есть два типа компонентов:
- Классовые компоненты (основанные на классах)
- Функциональные компоненты (компоненты, основанные на функциях)
Начнем с разбора классовых компонентов.
Классовые компоненты (stateful – обладают состоянием)
Компоненты, основанные на классах, как правило, имеют состояние и используются для того, чтобы вместе с реализацией какой-нибудь бизнес-логики, управлять внутренним состоянием компонента. В классовом компоненте можно использовать lifecycle-методы.
import React from "react"; const FunctionComponent = (props) => { return ( <div> <form> <input placeholder="Enter Term..." /> <button>Submit</button> </form> <div> <h1>{props.message}</h1> </div> </div> ); }; export default FunctionComponent;
state (состояние)
Состояние React-компонента (state) – объект, в котором находятся данные, которые могут изменяться со временем, т.е. Уже после того, как компонент был отрисован. Состояние – изменяемый (mutable) объект. Вы можете думать о state как о properties, которые могут влиять на поведение UI после первого рендера.
import React, { Component } from "react"; class App extends Component { state={firstname:'', lastname:''} render(){ return ( <div> <form> <input placeholder='firstname' value={this.state.firstname} onChange={(e)=>{this.setState({firstname:e.target.value})}} /> <input placeholder='lasttname' value={this.state.lastname} onChange={(e)=>{this.setState({lastname:e.target.value})}} /> <button onClick={(e)=>{e.preventDefault()}}>click</button> </form> </div> ) } } export default App
В приведенном коде на каждое событие keypress в input-e форм, происходит перерисовка (rerender) компонента и изменяется состояние UI.
Lifecycle-методы
Lifecycle-методы описывают весь жизненный цикл компонента от момента его инициализации до момента уничтожения (например, в результате закрытия страницы или удаления). Вот три главных lifecycle-метода:
componentDidMount
componentDidUpdate
componentWillUnmount
componentDidMount
Этот метод вызывается один раз – сразу после того, как компонент был отрисован. Вы можете использовать этот метод, чтобы загрузить данные, которые нужно показать сразу после отрисовки компонента браузером.
componentDidMount() { console.log('Я выполнился, как только отрендерился компонент') }
Код выше выведет в консоль надпись “Я выполнился, как только отрендерился компонент.” сразу после того, как отрендерится компонент.
componentDidUpdate
componentDidUpdate
вызывается, когда происходит изменения состояния уже отрисованного компонента. Метод принимает два аргумента – предыдущие properties и предыдущий state компонента.
componentDidUpdate(prevProps, prevState) { if (prevState.colors !== this.state.colors) { console.log('colors has changed.') } }
componentDidUpdate
вызывается в случае, если предыдущее состояние компонента не равно следующему состоянию.
componentWillUnmount
Метод вызывается, когда компонент удаляется из DOM-дерева. Это последний метод из жизненного цикла компонента. Тут можно разместить код, который должен быть выполнен прямо перед удалением компонента – например, удалить ненужные данные.
componentWillUnmount(){ console.log('Прямо сейчас произойдет удаление компонента.'); }
Код выше выведет в консоль текст прямо перед удалением компонента.
Функциональные компоненты (stateless)
Функциональные (stateless) компоненты – компоненты без состояния. Это обычная JavaScript функция, возвращающая JSX. Используются для того, чтобы получить props и отрисовать JSX. Функциональный компонент не управляет состоянием (на самом деле, есть способ – мы рассмотрим его ниже), таким образом, не может вызывать собственную перерисовку.
import React from "react"; const FunctionComponent = (props) => { return ( <div> <form> <input placeholder="Enter Term..." /> <button>Submit</button> </form> <div> <h1>{props.message}</h1> </div> </div> ); }; export default FunctionComponent;
Код выше создает функциональный компонент, возвращающий JSX с input-элементом и кнопкой Submit и заголовком h1, показывающим сообщение из props. Props в этот компонент будут приходить из компонента верхнего уровня.
Функциональные компоненты, как правило, используются, когда нет необходимости управлять состоянием или использовать lifecycle-методы. НО, с помощью хуков функциональный компонент может реагировать на изменения UI.
Хуки позволяют “захватить” состояние в функциональном компоненте – для этого используется useState хук. Lifecycle-методами можно пользоваться с помощью хука useEffect
.
useState
useState
в функциональном компоненте делает то же, что делает setState
в классовом компоненте.
import React from "react"; const FunctionalInput = () => { const [state, setstate] = React.useState({ firstname: "", lastname: "" }); const handleClick = (e) => { setstate(e.target.value); console.log(e.target.value); }; return ( <div> <input value={state.firstname} onChange={handleClick} placeholder="firstname" /> <input value={state.lastname} onChange={handleClick} placeholder="lastname" /> </div> ); }; export default FunctionalInput;
Код выше показывает, как пользоваться хуком useState
для управления состоянием в функциональном компоненте.
useEffect
useEffect
имеет что-то общее с lifecycle-методами в классовых компонентах. Это функция, которой передается другая функция, которая, в свою очередь, будет вызвана после того, как будет отрисован UI (так же, как componentDidMount
).
import React, { useEffect } from "react"; const FunctionalInput = () => { const [state, setstate] = React.useState({ firstname: "", lastname: "" }); //This piece of code runs after the ui has been rendered useEffect(() => { console.log("A component was rendered!!!"); }, []); const handleClick = (e) => { setstate(e.target.value); console.log(e.target.value); }; return ( <div> <input value={state.firstname} onChange={handleClick} placeholder="firstname" /> <input value={state.lastname} onChange={handleClick} placeholder="lastname" /> </div> ); }; export default FunctionalInput;
useEffect
в коде выше будет вызван сразу после того, как будет отрисован UI. Вторым параметром в useEffect
передается пустой массив – в этом случае метод в useEffect
не будет вызываться каждый раз, когда перерисовывается UI. В useEffect
можно делать запросы к API – каждый раз, когда перерисовывается UI и меняются параметры, которые влияют на данные, которые должны быть показаны – удобно запрашивать их именно в useEffect
.
В React вы можете создавать свои собственные хуки – это дает широкие возможности для их применения. Но, используются они только в функциональных компонентах.
Два типа компонентов, описанные в статье, могут быть использованы в зависимости от того, что вы разрабатываете. Важно понимать, как работают и функциональные, и классовые компоненты.