# Создание функционального компонента - Создаем функцию компонент - Знакомимся с хуками - Практический пример создания функциональных компанент ## Чистые функции и их преимущества 1. Легко тестировать 2. Предсказуемость поведения. При одинаковых входных данных ответ всегда тот же. ```javascript let ctx = 10; function addUnpure(a, b) { return ctx + a + b; } addUnpure(7, 5); // 22 addUnpure(7, 5); // 22 addUnpure(11, 15); // 36 ctx = 5; addUnpure(7, 5); // 17 function add(a, b) { return a + b; } ``` ## Создание функционального компонента Функциональный компонент - обычная JavaScript функция. То, что она возвращает, совпадает с результатом вызова метода *render()* классового компонента ```javascript function App () { return ( <> <Title className="app-title" title="Наведи на меня" style={{backgroundColor: 'red'}}>Pokemon List {process.env.REACT_APP_BOBIK}</Title> <PokemonListLoader count={50} /> </> ); } ``` ## Класс или функция В большинстве случаев в современном React проще использовать функциональные компоненты. В ряде случаев классы являются более подходящим инструментом: 1. Прямой доступ к DOM-дереву 2. Управление обновлением компонентов Подробнее можно ознакомиться на странице [документации](https://ru.reactjs.org/docs/react-component.html) ## React Fragment в JSX Вместо React.Fragment можно писать более удобную форму: <></> ## Хуки, useState С помощью хуков можно забыть про проблемы потери контекста и управления им, а также this.state и метод this.setState. ## Жизненный цикл компонента, useEffect useEffect вызывается единожды при условии, что параметры, от которых он зависит, не будут меняться. С каждым изменением значения в массиве параметров, функция в useEffect будет вызываться повторно. ```jsx useEffect(() => { (async () => { setLoading(LOADING_PROGRESS); const newData = await loadData(count); setLoading(LOADING_END); setData(newData.results); })(); }, [count]); ``` ## Правила использования хуков 1. Вызывать хуки только из React-компонентов 2. Использовать хуки только на верхнем уровне 3. Сохранить порядок вызова хуков и их количество [Подробнее](https://ru.reactjs.org/docs/hooks-rules.html) ## Props Children С помощью children можно передавать в компонент дочерние узлы ```jsx import C from "classnames"; export const Title = (props) => { const className = C('title', props.className); return <h1 {...props} className={className}>{props.children}</h1>; } ``` ```jsx <Title className="app-title" title="Наведи на меня" style={{backgroundColor: 'red'}}>Pokemon List {process.env.REACT_APP_BOBIK}</Title> ``` ## Prop Types Библиотека позволяет отследить правильность использования props на этапе разработки. ```jsx import PropTypes from 'prop-types'; import { Pokemon } from '../molecules/Pokemon'; import { LOADING_PROGRESS, LOADING_END } from '../../constants.js'; export function PokemonList ({ loading, data = []}) { return (<> {loading === LOADING_PROGRESS && <span className="loading">Загрузка...</span>} {loading === LOADING_END && <div className='pokemon-list'> {data.map(({ name }, index) => <Pokemon key={index} name={name}/>)} </div>} </>); } PokemonList.propTypes = { loading: PropTypes.bool, data: PropTypes.arrayOf(PropTypes.object) } ``` ## Компоненты-обёртки (Proxy component) Любой компонент, не имеющий состояния и внутренней логики. Отображает данные на основе переданных props ```jsx export function Pokemon({ name }) { return <div className='pokemon-list__item'> <div className='pokemon-list__name'> {name} </div> </div>; } ``` ## Компоненты высшего порядка (Higher-order component) Функция, которая возвращает компонент ```jsx import { useState, useEffect } from 'react'; import PropTypes from 'prop-types'; import { loadData } from '../../api.js'; import { LOADING_INIT, LOADING_PROGRESS, LOADING_END } from '../../constants.js'; export function withPokemonLoader (Component) { function PokemonListLoader({ count }) { const [loading, setLoading] = useState(LOADING_INIT); const [data, setData] = useState([]); useEffect(() => { (async () => { setLoading(LOADING_PROGRESS); const newData = await loadData(count); setLoading(LOADING_END); setData(newData.results); })(); }, [count]); return <Component loading={loading} data={data}/>; } PokemonListLoader.propTypes = { count: PropTypes.number }; return PokemonListLoader; } ``` ## Atomic Design Концепция предлагает разделение частей дизайна на следующие составляющие 1. Атомы 2. Молекулы 3. Организмы 4. Шаблоны 5. Страницы ### Атомы Мельчайшие элементы frontend-структуры ### Молекулы Композиция на основе нескольких атомов ### Организмы Композиция из нескольких молекул и атомов, может иметь состояние ### Шаблоны Заготовка страницы, содержит композицию всех необходимых компонентов, но без данных ### Страницы Шаблон с переданными ему данными