Не существует ли простого способа передать дочерний элемент props
его родителю с помощью событий в React.js?
var Child = React.createClass({
render: function() {
<a onClick={this.props.onClick}>Click me</a>
}
});
var Parent = React.createClass({
onClick: function(event) {
// event.component.props ?why is this not available?
},
render: function() {
<Child onClick={this.onClick} />
}
});
Я знаю, что вы можете использовать контролируемые компоненты для передачи значения ввода, но было бы неплохо передать весь комплект n 'kaboodle. Иногда дочерний компонент содержит набор информации, который вам не нужно искать.
Возможно, есть способ привязать компонент к событию?
ОБНОВЛЕНИЕ - 01.09.2015
После использования React в течение года, и подстрекаемый ответ Sebastien Лорбер, я пришел к выводу , проходя дочерние компоненты в качестве аргументов функций родителей не на самом деле React путь, и не было его никогда не является хорошей идеей. Я поменял ответ.
javascript
reactjs
KendallB
источник
источник
Ответы:
Изменить : см. Конечные примеры для обновленных примеров ES6.
Этот ответ просто обрабатывает случай прямых родительских отношений. Если у родителя и ребенка потенциально много посредников, проверьте этот ответ .
Другие решения не имеют смысла
Хотя они все еще работают нормально, в других ответах не хватает чего-то очень важного.
У родителя уже есть эта детская опора! : если у ребенка есть опора, то это потому, что его родитель предоставил опору ребенку! Почему вы хотите, чтобы ребенок передал опору родителю, в то время как у родителя уже есть эта опора?
Лучшая реализация
Ребенок : это действительно не должно быть сложнее, чем это.
Родитель с единственным ребенком : используя значение, которое он передает ребенку
JsFiddle
Родитель со списком детей : у вас все еще есть все, что нужно от родителя, и вам не нужно усложнять ребенка.
JsFiddle
Также возможно использовать,
this.handleChildClick.bind(null,childIndex)
а затем использоватьthis.state.childrenData[childIndex]
Обратите внимание, что мы связываемся с
null
контекстом, потому что в противном случае React выдает предупреждение, относящееся к его системе автосвязывания . Использование null означает, что вы не хотите изменять контекст функции. Смотрите также .Про инкапсуляцию и сцепление в других ответах
Для меня это плохая идея с точки зрения связывания и инкапсуляции:
Использование реквизитов : как я объяснил выше, у вас уже есть реквизиты в родительском элементе, поэтому бесполезно передавать весь дочерний компонент для доступа к реквизитам.
Использование ссылок : у вас уже есть цель клика в событии, и в большинстве случаев этого достаточно. Кроме того, вы могли бы использовать ссылку непосредственно на ребенка:
И получить доступ к узлу DOM в родительском с
В более сложных случаях, когда вы хотите получить доступ к нескольким ссылкам дочернего элемента в родительском элементе, дочерний элемент может передать все узлы dom непосредственно в обратный вызов.
Компонент имеет интерфейс (реквизит), и родительский объект не должен предполагать ничего о внутренней работе дочернего элемента, включая его внутреннюю структуру DOM или о том, для каких узлов DOM он объявляет ссылки. Родитель, использующий ссылку на ребенка, означает, что вы тесно связываете 2 компонента.
Чтобы проиллюстрировать проблему, я возьму цитату о Shadow DOM , которая используется внутри браузеров для рендеринга таких вещей, как ползунки, полосы прокрутки, видеоплееры ...:
Проблема заключается в том, что если вы позволите деталям дочерней реализации проникнуть в родительский объект, вам будет очень сложно провести рефакторинг дочернего элемента, не затрагивая родительский элемент. Это означает, что для автора библиотеки (или для редактора браузера с Shadow DOM) это очень опасно, потому что вы позволяете клиенту слишком много доступа, что усложняет обновление кода без нарушения ретро-совместимости.
Если Chrome реализовал свою полосу прокрутки, позволяющую клиенту получить доступ к внутренним узлам dom этой полосы прокрутки, это означает, что у клиента может быть возможность просто сломать эту полосу прокрутки, и что приложения будут ломаться легче, когда Chrome выполнит свое автоматическое обновление после рефакторинга полоса прокрутки ... Вместо этого они предоставляют доступ только к некоторым безопасным вещам, таким как настройка некоторых частей полосы прокрутки с помощью CSS.
Об использовании чего-либо еще
Передача всего компонента в обратном вызове опасна и может привести к тому, что начинающие разработчики будут делать очень странные вещи, такие как вызов
childComponent.setState(...)
илиchildComponent.forceUpdate()
, или присваивание ему новых переменных, внутри родительского элемента, что усложняет рассмотрение всего приложения.Изменить: ES6 примеры
Так как многие люди сейчас используют ES6, вот те же примеры для синтаксиса ES6
Ребенок может быть очень простым:
Родитель может быть либо классом (и он может в конечном итоге управлять самим состоянием, но я передаю его как подпорку здесь:
Но это также можно упростить, если не нужно управлять состоянием:
JsFiddle
ПРЕДУПРЕЖДЕНИЕ О ПРОИЗВОДИТЕЛЬНОСТИ (применимо к ES5 / ES6): если вы используете
PureComponent
илиshouldComponentUpdate
, вышеприведенные реализации не будут оптимизированы по умолчанию из-за использованияonClick={e => doSomething()}
или привязки непосредственно во время фазы рендеринга, потому что она будет создавать новую функцию каждый раз при рендеринге родительского объекта. Если это узкое место в вашем приложении, вы можете передать данные дочерним элементам и повторно внедрить их в «стабильный» обратный вызов (установленный в родительском классе и связанный сthis
конструктором класса), чтобыPureComponent
оптимизация могла сработать, или вы может реализовать свой собственныйshouldComponentUpdate
и игнорировать обратный вызов в проверке сравнения реквизита.Вы также можете использовать библиотеку Recompose , которая предоставляет компоненты более высокого порядка для оптимизации настройки:
В этом случае вы можете оптимизировать дочерний компонент, используя:
источник
props
. Согласен?How do I know which of my children was chosen among a group?
самом деле это не часть первоначального вопроса, но я включил решение в свой ответ. В отличие от вашего редактирования, я думаю, что совсем не обязательно изменять дочерний элемент, даже когда он имеет дело со списком, поскольку вы можете использовать егоbind
непосредственно в родительском элементе.onClick={this.handleChildClick.bind(null,childData)}
вы упомянули об автосвязывании. Это применимо и сейчас, когда React не включен в модель класса . Я прочитал много вещей, но эта часть все еще смущает меня.class model
Кстати, я использую ES6 , поэтому я перешелnull
наthis
и мой код все еще работает. Как бы вы перевели эту часть своего кода в стиле ES6?Обновление (1/1/15): ОП сделал этот вопрос немного движущейся целью. Это было обновлено снова. Поэтому я чувствую ответственность за обновление моего ответа.
Сначала ответьте на предоставленный пример:
Да, это возможно
Вы можете решить эту проблему, обновив Child's
onClick
следующим образомthis.props.onClick.bind(null, this)
:Обработчик событий в вашем Parent может затем получить доступ к компоненту и событию следующим образом:
Снимок JSBin
Но сам вопрос вводит в заблуждение
Родитель уже знает ребенка
props
.Это не ясно в приведенном примере, потому что на самом деле никакие реквизиты не предоставляются. Этот пример кода может лучше поддержать задаваемый вопрос:
В этом примере становится намного понятнее, что вы уже знаете, что такое реквизит ребенка.
Снимок JSBin
Если это действительно об использовании реквизита ребенка ...
Если речь идет об использовании реквизита ребенка, вы можете вообще избежать всякого контакта с ребенком.
JSX имеет API атрибутов распространения, который я часто использую в таких компонентах, как Child. Он берет все
props
и применяет их к компоненту. Ребенок будет выглядеть так:Позволяет вам использовать значения непосредственно в Parent:
Снимок JSBin
И при подключении дополнительных дочерних компонентов дополнительная настройка не требуется
Снимок JSBin
Но я подозреваю, что это не ваш случай. Итак, давайте копать дальше ...
Надежный практический пример
Об общем характере представленного примера сложно говорить. Я создал компонент, который демонстрирует практическое использование вышеуказанного вопроса, реализованный в стиле Reacty :
Рабочий пример
DTServiceCalculator DTServiceCalculator РЕПО
Этот компонент представляет собой простой сервисный калькулятор. Вы предоставляете ему список услуг (с именами и ценами), и он рассчитывает итоговые цены.
Дети блаженно невежественны
ServiceItem
является дочерним компонентом в этом примере. У него не так много мнений о внешнем мире. Это требует несколько реквизита , один из которых является функция, которая вызывается при нажатии.<div onClick={this.props.handleClick.bind(this.props.index)} />
Он ничего не делает, кроме как вызывает предоставленный
handleClick
обратный вызов с предоставленнымindex
[ источником ].Родители дети
DTServicesCalculator
является родительским компонентом этого примера. Это тоже ребенок. Давайте смотреть.DTServiceCalculator
создает список дочерних компонентовServiceItem
и предоставляет им реквизиты [ источник ]. Это родительский компонент,ServiceItem
но это дочерний компонент компонента, передающий ему список. Он не владеет данными. Поэтому он снова делегирует обработку компонента к родительскому-компонент источника<ServiceItem chosen={chosen} index={i} key={id} price={price} name={name} onSelect={this.props.handleServiceItem} />
handleServiceItem
захватывает индекс, переданный от потомка, и предоставляет его родителю [ источник ]Владельцы знают все
Концепция «собственности» является важной в React. Я рекомендую прочитать больше об этом здесь .
В примере, который я показал, я продолжаю делегировать обработку события в дереве компонентов, пока мы не доберемся до компонента, которому принадлежит состояние.
Когда мы наконец доберемся туда, мы обработаем выбор / отмену выбора состояния следующим образом: [ source ]:
Вывод
Постарайтесь, чтобы ваши внешние компоненты были максимально непрозрачными. Старайтесь убедиться, что у них очень мало предпочтений относительно того, как родительский компонент может их реализовать.
Имейте в виду, кто владеет данными, которыми вы манипулируете. В большинстве случаев вам нужно будет делегировать обработку события по дереву компоненту, которому принадлежит это состояние.
Кроме того: паттерн Flux - это хороший способ уменьшить необходимый тип подключения в приложениях.
источник
Parent
может быть такой Controller-View, аChild
просто dumb-View (компонент). Только Controller-Views должны иметь знания о приложении. В этом случае, вы бы еще пройти Акцию отParent
до вChild
качестве опоры. Что касается самого действия, Flux имеет строго предписанный шаблон взаимодействия между действиями для обновления представлений. facebook.github.io/flux/docs/…onClick={this.onClick.bind(null, this.state.text)}
нет необходимости связывать состояние, поскольку родитель имеет это. так простоonClick={this.onClick}
будет работать. гдеonClick = ()=>{const text = this.state.text;..}
у родителейПохоже, есть простой ответ. Учти это:
Ключ вызов
bind(null, this)
наthis.props.onClick
событии, передается от родителей. Теперь функция onClick принимает аргументыcomponent
ANDevent
. Я думаю, что это лучшее из всех миров.ОБНОВЛЕНИЕ: 01.09.2015
Это была плохая идея: позволить дочерним деталям реализации просочиться к родителю никогда не было хорошим путем. Смотри ответ Себастьяна Лорбера.
источник
this
функции (которая в любом случае не нужна), а второй добавляется в качестве первого аргумента при вызове onClick.Вопрос в том, как передать аргумент от дочернего к родительскому компоненту. Этот пример прост в использовании и проверен:
Посмотрите на JSFIDDLE
источник
В основном вы используете реквизит для отправки информации от и к ребенку и родителю.
В дополнение ко всем замечательным ответам позвольте мне привести простой пример, объясняющий передачу значений от дочернего к родительскому компоненту в React.
App.js
Header.js
Main.js
Вот и все, теперь вы можете передавать значения с вашего клиента на сервер.
Посмотрите на функцию Change в Header.js
Вот как вы толкаете значения в реквизит от клиента к серверу
источник
Вот простая трехэтапная реализация ES6 с использованием привязки функции в родительском конструкторе. Это первый способ, который рекомендует официальный учебник по реагированию (здесь также не описывается синтаксис полей публичных классов). Вы можете найти всю эту информацию здесь https://reactjs.org/docs/handling-events.html
Связывание родительских функций, чтобы дети могли вызывать их (и передавать данные родителю!: D)
Родительская функция
Родительский конструктор
Опора передана ребенку
Детское событие
источник
Это пример без использования события onClick. Я просто передаю функцию обратного вызова ребенку с помощью реквизита. С этим обратным вызовом дочерний вызов также отправляет данные обратно. Я был вдохновлен примерами в документах .
Небольшой пример (это в tsx файлах, поэтому реквизиты и состояния должны быть полностью объявлены, я удалил некоторую логику из компонентов, так что это меньше кода).
* Обновление: важно связать это с обратным вызовом, в противном случае обратный вызов имеет область дочернего, а не родительского. Единственная проблема: это «старый» родитель ...
SymptomChoser является родителем:
Симптом является дочерним (в подпорках дочернего я объявил функцию обратного вызова, в функции selectedSymptom вызывается обратный вызов):
источник