Как передать state из одного компонента в другой
Костыльный и непонятный выход. Для чего вы используете контекст в функциональном компоненте? Или же компонент, в котором находится FilterMobile является классом? Тогда нужно было сразу уточнить.
11 мар 2022 в 4:50
Ну так вы почти правильно всё делаете. Я про сам метод передачи в другой компонент. А вот проблема у вас сейчас в том, что вы пытаетесь использовать обычный функциональный компонент, как классовый. Определитесь, какой он должен быть: классовый или функциональный? Если всё-таки функциональный, то просто вызовите функцию при клике (например), но не используйте this.setState (это установка стейта в классовом компоненте) как-то так: onClick= tokensCount()>
Если компонент, должен стать классовым, то его нужно переписать иначе: унаследовать React.Component, добавить метод render и т.д.
Вот как можно использовать то, о чем я писал выше:
import < useState >from "react"; import "./styles.css"; export default function App() < let [count, setCount] = useState(0); let tokensCount = () => < setCount(count + 1) >return ( count: /> ); > const FilterMobile = () => < return ( ) >
Передача данных между компонентами в React
В реакте поток данных — однонаправленный. Это значит что данные передаются как водопад, сверху вниз, от родителя к ребенку, через props. Что такое props? Это неизменяемый объект, предназначенный только для чтения. Проще понять если думать о компонентах, как о функциях(а они по сути ими и являются), props—это просто аргумент функции, с которым мы можем работать внутри, но не изменять.
Родитель ➡️ Ребенок — используй Props
Это самый простой способ передачи данных.
1. В родительском компоненте передаём данные из стейта в дочерний.
2. В дочернем принимаем и выводим.
Props:
Родитель ⬅️ Ребенок — используй Callback
Эта передача данных напоминает мне бумеранг, есть точка старта — это наш родительский компонент, есть точка максимального отдаления — это дочерний компонент. И есть наш инструмент —бумеранг, в реакте это будет функция, которая находится в родителе и передаётся через props в ребенка, где и вызывается.
1. Создаём в родителе функцию updateData . У неё есть входной параметр value , этот параметр мы присваиваем в стейт нашего компонента, с помощью функции setState . Бумеранг готов!
updateData = (value) => this.setState(< name: value >)>
2. Передаём в дочерний элемент через props функцию updateData . Мы запустили бумеранг 🙂
3. В дочернем элементе я создала кнопку, при клике на неё будет вызываться функция, которую мы передавали с помощью props. Ей передается новый параметр для текста, именно его мы хотим передать в родителя. Бумеранг возвращается назад.
Ребенок ➡️ Ребенок—используй родителя.
Для того чтобы передать данные между соседними компонентами, нужно использовать посредника—их родителя. Сначала нужно передать данные от ребенка к родителю как аргумент коллбека. Потом присвоить эти данные в стейт родителя и передать через props другому компоненту.
Передача стейта в дочерний компонент в React
В прошлой статье «Дочерний компонент в React» было показано как вызывать компонент из компонента. В этой статье доработаем наш код небольшого интенет магазина. Добавим в него кнопку добавления товара в корзину. А чтобы состояние товара запоминалось, введём в начальный массив логическое свойство «inCart», а сам массив будем записывать в стейт, чтобы срабатывали механизмы реактивности.
Сначала модифицируем стартовый массив:
const shopItems = [ , , , ];
Теперь изменим компонент с выводом списка продуктов(«Products»), добавив в него стейт:
function Products() < const [prods, setProds] = useState(shopItems); const result = prods.map(prod => < return name= price= inCart= />; >); return ; >
И чтобы вся система с добавлением товаров в корзину работала, необходимо добавить кнопку для этого действия в карточку товара (в компонент «Product»):
function Product(< id, name, price, inCart >) < return Товар: , Цена: , , ; >
Мы хотим, чтобы при нажатии на кнопку «Добавить в корзину» у товара менялось свойство «inCart» на значение «true»:
function addToCart(id) < setProds(prods.map(prod => < if (prod.id == id) < prod.inCart = true; >return prod; >)); >
По правилам React сам компонент не должен изменять свои принимаемые аргументы (свойства). То есть на уровне компонента «Product» декларировать эту функцию. Поэтому придётся её переместить в родительский компонент. А в дочерний компонент будем передавать указатель на эту функцию. То есть в компоненте «Products» получится так:
const result = prods.map(prod => < return name= price= inCart= addToCart= />; >);
Остаётся только добавить событие на кнопку добавления товара в корзину компонента «Product». По клику будем вызывать функцию добавления и передавать ей id нужного товара
function Product(< id, name, price, inCart, addToCart >) < return Товар: , Цена: , , ; >
Так в дочернем компоненте будет вызываться функция, которая декларирована в родителе. React распознает изменения и перерендерит страницу, отобразив успешное добавление товара в корзину.
Как передавать данные между компонентами в ReactJS

В React можно разными способами передавать данные между компонентами. Применимость каждого способа определяется направлением движения данных. Данные могут двигаться от дочернего компонента к родительскому или наоборот. Данные могут двигаться глубоко — от корневого элемента до элемента-потомка. Данными могут обмениваться соседние элементы. В этой статье мы рассмотрим как передавать данные в каждом конкретном случае.
- от родительского компонента к дочернему;
- от дочернего компонента к родительскому;
- между соседними компонентами;
- от компонента к компоненту-потомку (через несколько уровней вниз);
- от компонента к компоненту-предку (через несколько уровней вверх).
- через пропсы;
- используя callback-функцию;
- пробросом пропсов от уровня к уровню (prop drilling);
- при помощи контекста (React Context AP);
- через хранилище (store);
От родительского компонента к дочернему
Наиболее простой и часто встречающийся случай — это случай, когда дочерний компонент принимает данные от родителя через пропсы.
import < useState >from 'react' const Parent = () => < const [value, setValue] = useState('') const handleChange = (event) => < setValue(event.target.value) >return ( />* передаем проп в дочерний компонент */> /> ) > const Child = (< value >) => < return ( Value is: '> ) >
От дочернего компонента к родительскому
Если необходимо передать данные от дочернего реакт компонента к родительскому, используются функции обратного вызова (callback-функции).
import < useState >from 'react' const Child = (< onChange >) => < const handleChange = (event) => < onChange(event.target.value) // callback-функция >return ( /> ) > const Parent = () => < const [value, setValue] = useState('') const handleChange = (value) => < setValue(value) >return ( Value is: '> /> ) >
Между соседними компонентами
Данные между соседними компонентами, т.е. между компонентами на одном уровне, можно передать через общий предок. Обычно данные от одного Реакт компонента передаются вверх, в компонент-предок, через callback-функцию, а компонент-предок передает их в другой компонент через проп.
import < useState >from 'react' const Parent = () => < const [value, setValue] = useState('') const handleChange = (value) => < setValue(value) >return ( /> /> ) > const Sibling1 = (< onChange >) => < const handleChange = (event) => < onChange(event.target.value) >return ( /> ) > const Sibling2 = (< value>) => < return ( Value is: '> ) >
Через несколько уровней вверх/вниз
Если компоненты находится в несколько уровнях друг от друга, то также можно передать проп. Этот проп придется описывать во всех компонентах на всех промежуточных уровнях. Эта ситуация называется prop drilling. Если уровней много, то такой способ покажется не очень удобным. Если нужно передавать данные на несколько уровней вверх, то также придется описывать и вызывать callback-функцию на всех промежуточных уровнях. Однако, в подобных случаях можно использовать Context API (пример которого приведен ниже), или state management библиотеки, такие как Redux, MobX, Recoil и т.д.
import < useState, useContext, createContext >from 'react' // создаем контекст const ValueContext = createContext() // Component1 записывает данные в контекст ValueContext const Component1 = () => < const < setValue >= useContext(ValueContext) const handleChange = (event) => < setValue(event.target.value) >return ( /> ) > // Component2 читает данные из контекста ValueContext const Component2 = () => < const < value >= useContext(ValueContext) return ( Value is: '> ) > // компоненты, которым необходим доступ к контексту, // должны быть обернуты в Provider export default function App() < const [value, setValue] = useState('') return ( >> ) >
Очередь обновлений состояния в React

4 месяца назад · 6 мин. на чтение
Установка переменной состояния поставит в очередь следующий рендеринг. Но иногда нужно выполнить несколько операций над значением перед постановкой в очередь следующего рендеринга. Для этого полезно понять, как React пакетно обновляет состояние (батчинг).
Содержание туториала по React Установка переменной состояния поставит в очередь следующий рендеринг. Но иногда нужно выполнить несколько операций над значением перед постановкой в очередь следующего рендеринга. Для этого полезно понять, как React пакетно обновляет состояние (батчинг).
React батчит обновления состояний
Батчинг - это объединение обновлений в одну операцию. В следующем примере, вы можете ожидать, что нажатие кнопки «+3» увеличит счетчик три раза, потому что он трижды вызывает setNumber(number + 1) :
import < useState >from 'react'; export default function Counter() < const [number, setNumber] = useState(0); return ( <> >); >
Однако, как вы, возможно, помните из предыдущего раздела, значения состояния каждого рендеринга фиксированы, поэтому значение number внутри обработчика событий первого рендеринга всегда равно 0 , независимо от того, сколько раз вы вызываете setNumber(1) :
setNumber(0 + 1); setNumber(0 + 1); setNumber(0 + 1);
Но здесь есть еще один фактор, который нужно обсудить. React ждет, пока весь код в обработчиках событий будет запущен, прежде чем обрабатывать ваши обновления состояния. Вот почему повторный рендеринг происходит только после всех этих вызовов setNumber() . Это может напомнить вам официанта, принимающего заказ в ресторане. Официант не бежит на кухню при упоминании вашего первого блюда. Вместо этого они позволяют вам закончить свой заказ, позволяют вносить в него изменения и даже принимать заказы от других людей за столом. Это позволяет вам обновлять несколько переменных состояния — даже из нескольких компонентов — без запуска слишком большого количества повторных рендерингов. Но это также означает, что пользовательский интерфейс не будет обновляться до тех пор, пока ваш обработчик событий и любой код в нем не завершится. Такое поведение, также известное как пакетная обработка (батчинг), позволяет вашему приложению React работать намного быстрее. Это также позволяет избежать сбивающих с толку «недоделанных» рендеров, в которых были обновлены только некоторые переменные. React не объединяет несколько преднамеренных событий, таких как клики, — каждый клик обрабатывается отдельно. Будьте уверены, что React выполняет пакетную обработку только тогда, когда это в целом безопасно. Это гарантирует, что, например, если первый клик кнопки отключит форму, второй щелчок не отправит ее снова.
Обновление одной и той же переменной состояния несколько раз перед следующим рендерингом
Это необычный вариант использования, но если вы хотите обновить одну и ту же переменную состояния несколько раз перед следующим рендерингом, вместо передачи следующего значения состояния, такого как setNumber(number + 1) , вы можете передать функцию, которая вычисляет следующее состояние. на основе предыдущего в очереди, например setNumber(n => n + 1) . Это способ сказать React «сделать что-нибудь со значением состояния», а не просто заменить его. Вот как это выглядит на практике:
import < useState >from 'react'; export default function Counter() < const [number, setNumber] = useState(0); return ( <> >); >
- React ставит эту функцию в очередь для обработки после выполнения всего остального кода в обработчике событий.
- Во время следующего рендеринга React проходит через очередь и выдает вам окончательное обновленное состояние.
setNumber((n) => n + 1); setNumber((n) => n + 1); setNumber((n) => n + 1);
- setNumber(n => n + 1) : n => n + 1 — это функция. React добавляет его в очередь.
- setNumber(n => n + 1) : n => n + 1 — это функция. React добавляет его в очередь.
- setNumber(n => n + 1) : n => n + 1 — это функция. React добавляет его в очередь.
запланированное обновление
n
возвращает
n => n + 1
0
0 + 1 = 1
n => n + 1
1
1 + 1 = 2
n => n + 1
2
2 + 1 = 3
React сохраняет 3 в качестве конечного результата и возвращает его из useState . Вот почему нажатие «+3» в приведенном выше примере корректно увеличивает значение на 3 .
Что произойдет, если вы обновите состояние после его замены
А как насчет этого обработчика событий? Как вы думаете, какое число будет в следующем рендере?
< setNumber(number + 5); setNumber(n =>n + 1); >>>
import < useState >from 'react'; export default function Counter() < const [number, setNumber] = useState(0); return ( <> >); >
- setNumber(number + 5) : number равно 0 , поэтому получаем setNumber(0 + 5) . React добавляет в свою очередь «заменить на 5».
- setNumber(n => n + 1) : n => n + 1 — это функция обновления. React добавляет эту функцию в свою очередь.
запланированное обновление
n
возвращает
"заменить на 5"
0 (не используется)
5
n => n + 1
5
5 + 1 = 6
React сохраняет 6 в качестве конечного результата и возвращает его из useState . Вы могли заметить, что setState(x) на самом деле работает как setState(n => x) , но n не используется.
Что произойдет, если вы замените состояние после его обновления
Давайте попробуем еще один пример. Как вы думаете, какое число будет в следующем рендере?
< setNumber(number + 5); setNumber(n =>n + 1); setNumber(42); >>>
import < useState >from 'react'; export default function Counter() < const [number, setNumber] = useState(0); return ( <> >); >
- setNumber(number + 5) : number равно 0 , поэтому setNumber(0 + 5) . React добавляет в свою очередь «заменить на 5».
- setNumber(n => n + 1) : n => n + 1 — это функция обновления. React добавляет эту функцию в свою очередь.
- setNumber(42) : React добавляет в свою очередь «заменить на 42». Во время следующего рендера React проходит через очередь состояний:
запланированное обновление
n
возвращает
"заменить на 5"
0 (не используется)
5
n => n + 1
5
5 + 1 = 6
"заменить на 42"
6 (не используется)
42
- Функция обновления (например, n => n + 1 ) добавляется в очередь.
- Любое другое значение (например, число 5 ) добавляет в очередь «заменить на 5», игнорируя то, что уже находится в очереди.
Соглашения об именах
Аргумент функции обновления принято называть первыми буквами соответствующей переменной состояния:
setEnabled((e) => !e); setLastName((ln) => ln.reverse()); setFriendCount((fc) => fc * 2);
Если вы предпочитаете более подробный код, другим распространенным соглашением является повторение полного имени переменной состояния, например setEnabled(enabled => !enabled) , или использование префикса, такого как setEnabled(prevEnabled => !prevEnabled) .
Резюме
- Установка состояния не изменяет переменную в существующем рендеринге, но запрашивает новый рендеринг.
- React обрабатывает обновления состояния после завершения работы обработчиков событий. Это называется батчингом.
- Чтобы обновить некоторое состояние несколько раз в одном событии, вы можете использовать функцию обновления setNumber(n => n + 1) .