Статьи по React

Передача данных в компонент React

Компонент React – это объект кода, который на основе данных генерирует графический рендеринг в HTML. Другими словами, проще говоря, компоненты React – это функции, которые принимают значения на вход и возвращают HTML-код на выход.

В этой статье мы рассмотрим различные данные, используемые компонентами React для генерации HTML-кода.

Props (или свойства)

Компоненты используются как теги HTML (но таковыми не являются). Таким образом, свойства – это React-версия атрибутов HTML.

<MyComponent name="Первый компонент" placeholder="Загрузка первого компонента..." />
Code language: HTML, XML (xml)

MyComponent имеет следующие свойства:

  • name
  • placeholder

В реализации компонента мы можем получить их следующим образом:

function MyComponent(props) { const { name, placeholder } = props // ... }
Code language: JavaScript (javascript)

Props (или свойства) компонента позволяют передавать ему внешние данные из родительского контекста. То есть с того места, где он используется.

React будет отслеживать эти данные и перерисовывать компонент, если они обновляются. При изменении значений props React повторно выполнит функцию MyComponent с новыми значениями данных и получит сгенерированный ею HTML, чтобы соответствующим образом обновить DOM.

Обратите внимание, что поскольку свойства являются внешними данными для компонента, имеет смысл получать их через аргументы функции.

Состояния (или переменные состояния)

Обновление компонентов на основе внешних данных – распространенный вариант использования, но часто бывает, что компоненту необходимо хранить данные, которые пригодятся при следующем отображении.

Например, кнопка, отображающая количество нажатий на нее:

function CountButton() { let count = 0 return ( <button onClick={() => count += 1}> Нажмите на меня! (Кликнули {count} раз) </button> ) }
Code language: JavaScript (javascript)

Переменная count не является свойством, поскольку она специфична для компонента CountButton. Вне этого компонента она не будет иметь никакого значения.

Но, как заметили более проницательные из вас, мы также не можем объявить простую переменную в нашем компоненте. Таким образом, приведенный выше код не работает.

Причины следующие:

  • Мы сказали, что React использует функцию CountButton для рендеринга одноименного компонента. При каждом изменении свойств React вызывает функцию, которая будет выполнена, как обычная функция JavaScript. Поскольку count ограничен областью видимости функции, в начале функции его не существует, а после выполнения функции он больше не существует. Поэтому кнопка всегда будет отображать 0 кликов.
  • Мы хотим, чтобы кнопка отображала значение count при его изменении. Поэтому React должен перерисовать компонент, чтобы отобразить его новое состояние в DOM. Как React узнает, что переменная изменилась и что нам нужно перерисовать компонент? Он не может использовать переменные JavaScript.

Описанное нами поведение очень похоже на переменные экземпляра объектов в ООП (объектно-ориентированном программировании). К сожалению, в этой статье мы используем не объекты, а функции для создания наших компонентов.

В React есть инструмент, который позволяет сделать все, что нам нужно: хуки. В частности, нас интересует один хук – useState. Мы не будем подробно объяснять, что такое хуки. Мы просто посмотрим, как создать переменную состояния и как useState решает перечисленные выше проблемы.

function CountButton() { let [count, setCount] = useState(0) return ( <button onClick={() => setCount(count + 1)}> Нажмите на меня! (Кликнули {count} раз) </button> ) }
Code language: JavaScript (javascript)

С этим хуком мало что меняется. Мы просто делегируем создание count функции useState, передавая ей первое значение.

useState сохранит значение count в другом месте, а не в функции компонента, чтобы его можно было сохранить, несмотря на циклы рендеринга. Она также возвращает функцию модификации состояния. Функция change уведомляет React каждый раз, когда мы ее вызываем, чтобы он знал, что нужно снова отрисовать компонент.

Давайте проделаем этот процесс вручную, чтобы лучше понять его. В первый раз, когда React нужно отрисовать компонент, он запускает useState. useState ищет существующее состояние для count. Он не находит его и создает его со значением, переданным в качестве аргумента useState (0 для нас). Поэтому count равен нулю. React продолжает рендеринг компонента и отображает 0 в кнопке.

Когда пользователь нажимает на кнопку, вызывается setCount со значением 1. setCount изменяет значение состояния и предупреждает React о том, что что-то изменилось. React рендерит компонент, запускает useState. useState ищет существующее состояние для count. Он находит его и возвращает его текущее значение (1 для нас). Таким образом, count равен единице. React продолжает рендеринг компонента и отображает 1 в кнопке.

И так далее.

Контексты

Мы говорили о контекстах в разделе о свойствах компонентов. Напомним, что свойство используется для того, чтобы сделать значение непосредственно доступным в текущем контексте для дочернего компонента.

Таким образом он может делать с ним все, что захочет, и даже передавать его своим дочерним компонентам. И т.д. и т.п.

function ComponentOne(props) { return ( <> <ComponentTwo count={props.count} /> <ComponentThree count={props.count} /> </> ) } function ComponentTwo(props) { return <ComponentFour count={props.count} /> } function ComponentThree(props) { return <ComponentFive count={props.count} /> } function ComponentFour(props) { doSomething(props.count) return <ComponentSix count={props.count} /> } function ComponentFive(props) { doSomething(props.count) return <div /> } function ComponentSix(props) { doSomething(props.count) return <div /> }
Code language: JavaScript (javascript)

Это простое дерево, но уже в этом примере count используется в трех разных компонентах на разных уровнях дерева, в то время как по крайней мере в трех других компонентах среднего уровня он вообще не используется. Эти компоненты передают только данные.

В больших приложениях такое поведение может быстро сделать код более сложным для написания и сопровождения. Для решения этих проблем React предлагает контексты.

Их особенность заключается в том, что мы можем получить доступ к значениям, содержащимся в этих контекстах, из любой точки дерева компонентов.

Если мы возьмем приведенный ниже пример и добавим контексты, то он будет выглядеть следующим образом:

const CountContext = createContext(0) function ComponentOne(props) { return ( <CountContext.Provider value={props.count}> <ComponentTwo /> <ComponentThree /> </CountContext.Provider> ) } function ComponentTwo() { return <ComponentFour /> } function ComponentThree() { return <ComponentFive /> } function ComponentFour() { const count = useContext(CountContext) doSomething(count) return <ComponentSix /> } function ComponentFive() { const count = useContext(CountContext) doSomething(count) return <div /> } function ComponentSix() { const count = useContext(CountContext) doSomething(count) return <div /> }
Code language: JavaScript (javascript)

Мы создали Context Provider на уровне, где доступно значение. Отсюда все дочерние компоненты имеют доступ к контексту и, следовательно, к содержащимся в нем значениям. Только те компоненты, которым это необходимо, содержат код об этих значениях.

Значение, которое мы передаем в функцию createContext, является значением по умолчанию. Это позволяет использовать компоненты, которым необходимо значение контекста, в тех местах кода, где контекст недоступен. Например, если мы не пользовались услугами провайдера.

Выше я упоминал, что React Context немного более глобальный. Я имел в виду, что нам не нужно делать глобальный мегаконтекст а-ля redux для хранения всех значений в нашем приложении (хотя это возможно).

Контексты React были разработаны для локального использования там, где это необходимо. Они располагаются на определенном уровне дерева компонентов, не требуется создавать контекст на самом высоком уровне дерева. В этом отношении они не являются глобальными.

Мы также можем использовать несколько различных контекстов, которые будут содержать данные, относящиеся к определенной функциональности нашего приложения, нет необходимости использовать один общий контекст, содержащий все данные для приложения. Например, мы можем иметь один контекст для функциональности перевода, другой – для отображения сообщений, третий – для отображения всплывающих окон, третий – для тематического оформления наших компонентов и т.д. Таким образом, каждый контекст может занять свое место в приложении.

Поэтому каждый контекст может занять свое место на том уровне дерева компонентов, где он полезен. Мы даже можем использовать несколько экземпляров одного и того же контекста, чтобы не централизовать данные, когда это необходимо. Например, для предварительного просмотра влияния изменения языка на пользовательский интерфейс перед реальным изменением.

Мы рассмотрели 3 простых способа передачи информации в наши компоненты React:

  • props
  • состояния
  • контексты

Можно смешивать эти различные методы вместе для создания более умных компонентов, которые позволяют, например, родительским компонентам изменять начальное значение переменной состояния или которые знают, как непосредственно изменить значение, содержащееся в контексте, чтобы просто обновить другие соседние компоненты и т.д.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *