- Предположим, у меня есть класс React P, который отображает два дочерних класса, C1 и C2.
- C1 содержит поле ввода. Я буду называть это поле ввода Foo.
- Моя цель - позволить C2 реагировать на изменения в Foo.
У меня есть два решения, но ни одно из них не кажется правильным.
Первое решение:
- Присвоить P состояние,
state.input
. - Создайте
onChange
функцию в P, которая принимает событие и устанавливаетstate.input
. - Передайте это
onChange
C1 как aprops
, и пусть C1 свяжетсяthis.props.onChange
сonChange
Foo.
Это работает. Всякий раз, когда значение Foo изменяется, оно запускает a setState
в P, поэтому у P будет вход для передачи в C2.
Но это не совсем правильно по той же причине: я устанавливаю состояние родительского элемента из дочернего элемента. Похоже, это нарушает принцип разработки React: однонаправленный поток данных.
Это то, как я должен это делать, или есть более естественное решение React?
Второе решение:
Просто поместите Foo в P.
Но должен ли я следовать этому принципу проектирования при структурировании своего приложения - помещать все элементы формы в render
класс самого высокого уровня?
Как и в моем примере, если у меня большой рендеринг C1, я действительно не хочу помещать все render
C1 в render
P только потому, что C1 имеет элемент формы.
как мне это сделать?
Ответы:
Итак, если я правильно вас понимаю, ваше первое решение предполагает сохранение состояния в корневом компоненте? Я не могу говорить за создателей React, но в целом я считаю, что это правильное решение.
Поддержание состояния является одной из причин (по крайней мере, я так думаю) того, что React был создан. Если вы когда-либо реализовывали свою собственную клиентскую сторону шаблона состояний для работы с динамическим пользовательским интерфейсом, который имеет много взаимозависимых движущихся частей, то вам понравится React, потому что он значительно облегчает эту проблему управления состоянием.
Поддерживая состояние в иерархии и обновляя его с помощью событий, ваш поток данных все еще в значительной степени однонаправлен, вы просто реагируете на события в компоненте Root, вы на самом деле не получаете данные там посредством двухстороннего связывания, вы говорите компоненту Root, что «эй, здесь что-то случилось, проверьте значения», или вы передаете состояние некоторых данных в дочерний компонент, чтобы обновить состояние. Вы изменили состояние в C1, и вы хотите, чтобы C2 знал об этом, поэтому, обновляя состояние в Root-компоненте и повторной визуализации, реквизиты C2 теперь синхронизированы, так как состояние было обновлено в Root-компоненте и передано вместе. ,
источник
C2
естьgetInitialState
для данных и внутриrender
он используетthis.state.data
?Используя React для создания приложения сейчас, я хотел бы поделиться некоторыми мыслями по этому вопросу, который я задал полгода назад.
Я рекомендую вам прочитать
Первый пост чрезвычайно полезен для понимания того, как вы должны структурировать свое приложение React.
Flux отвечает на вопрос, почему вы должны структурировать свое приложение React таким образом (в отличие от того, как его структурировать). React - это всего лишь 50% системы, и с Flux вы можете увидеть всю картину и увидеть, как они составляют целостную систему.
Вернуться к вопросу.
Что касается моего первого решения, то вполне нормально, чтобы обработчик шел в обратном направлении, поскольку данные все еще идут в одном направлении.
Однако, может ли разрешение обработчика вызвать setState в P может быть правильным или неправильным в зависимости от вашей ситуации.
Если приложение представляет собой простой конвертер Markdown, C1 является необработанным вводом, а C2 является выводом HTML, то можно разрешить C1 запускать setState в P, но некоторые могут утверждать, что это не рекомендуемый способ сделать это.
Однако, если приложение является списком задач, C1 является входом для создания нового задания, C2 - списком задач в HTML, вы, вероятно, захотите, чтобы обработчик поднялся на два уровня выше, чем P - в
dispatcher
, что позволяетstore
обновлятьdata store
, которые затем отправляют данные в P и заполняют представления. Смотрите эту статью о Flux. Вот пример: Flux - TodoMVCКак правило, я предпочитаю способ, описанный в примере списка задач. Чем меньше у вас состояния в вашем приложении, тем лучше.
источник
Спустя пять лет с введением React Hooks появился намного более элегантный способ сделать это с помощью ловушки useContext.
Вы определяете контекст в глобальной области видимости, экспортируете переменные, объекты и функции в родительский компонент, а затем оборачиваете дочерние элементы в приложении в предоставленный контекст и импортируете все, что вам нужно, в дочерние компоненты. Ниже приведено подтверждение концепции.
Вы можете запустить этот пример в редакторе песочницы кода.
источник
Первое решение с сохранением состояния в родительском компоненте является правильным . Однако, для более сложных проблем, вы должны думать о какой - то государственной библиотеке управления , перевождь является наиболее популярной использовать с среагировать.
источник
Я удивлен, что в данный момент я не отвечаю на идиоматическое решение React. Итак, вот один (сравните размер и сложность с другими):
Любой контролируемый
input
(идиоматический способ работы с формами в React) обновляет родительское состояние в своем обратномonChange
вызове и по-прежнему ничего не выдает.Посмотрите внимательно на компонент C1, например. Видите ли вы существенную разницу в том, как
C1
встроенныйinput
компонент обрабатывает изменения состояния? Вы не должны, потому что нет ни одного. Поднятие состояния и передача пар value / onChange идиоматична для необработанного React. Не использование ссылок, как предполагают некоторые ответы.источник
this.state
, возвращаемое значение отсутствует при рендеринге, и несколько компонентов должны быть заключены в div или что-то еще. Не знаю, как я пропустил это, когда написал оригинальный ответ. Должно быть, это ошибка редактирования.Более свежий ответ с примером, который использует
React.useState
Сохранение состояния в родительском компоненте является рекомендуемым способом. Родитель должен иметь доступ к нему, поскольку он управляет им через два дочерних компонента. Перемещение его в глобальное состояние, подобное тому, которым управляет Redux, не рекомендуется по той же причине, почему глобальная переменная хуже, чем локальная в целом в разработке программного обеспечения.
Когда состояние находится в родительском компоненте, дочерний элемент может изменить его, если родительский элемент передает дочерний элемент
value
иonChange
обработчик в реквизитах (иногда это называется ссылкой на значение или шаблоном ссылки на состояние ). Вот как бы вы сделали это с помощью хуков:Весь родительский компонент будет повторно отображаться при изменении входных данных в дочернем элементе, что может не быть проблемой, если родительский компонент слишком мал / быстр для повторной визуализации. Производительность повторного рендеринга родительского компонента все еще может быть проблемой в общем случае (например, большие формы). Это решаемая проблема в вашем случае (см. Ниже).
Шаблон связи состояний и отсутствие родительского повторного рендеринга проще реализовать с помощью сторонней библиотеки, такой как Hookstate - с наддувом
React.useState
чтобы охватить различные варианты использования, включая ваш. (Отказ от ответственности: я автор проекта).Вот как это будет выглядеть с Hookstate.
Child1
изменит вход,Child2
отреагирует на это.Parent
будет удерживать состояние, но не будет повторно выполнять рендеринг при изменении состояния, толькоChild1
иChild2
будет.PS: здесь есть еще много примеров, охватывающих аналогичные и более сложные сценарии, включая глубоко вложенные данные, проверку состояния, глобальное состояние с
setState
перехватом и т. Д. Кроме того, в Интернете есть полный пример приложения , в котором используется Hookstate и методика, описанная выше.источник
Вы должны изучить библиотеки Redux и ReactRedux. Она структурирует ваши состояния и реквизиты в одном магазине, и вы сможете получить к ним доступ позже в ваших компонентах.
источник
С React> = 16.3 вы можете использовать ref и forwardRef, чтобы получить доступ к DOM ребенка от его родителя. Больше не используйте старый способ реферирования.
Вот пример использования вашего случая:
См Refs и ForwardRef подробной информации о ссылках и forwardRef.
источник
shouldComponentUpdate(nextProps, nextState)
Ниже используются
@bound
аннотаций от ES.Nextbabel-plugin-transform-decorators-legacy
из BabelJS 6 и класса-свойств (аннотация устанавливает это значение на функции членов , аналогичной затруднительный):источник
Концепция передачи данных от родителя к ребенку и наоборот объясняется.
источник