2015-06-16 3 views
3

Я работаю над приложением React, моим первым, и я борюсь с тем, как реализовать пользовательские интерактивные popovers. У меня есть бизнес-требование, чтобы иметь popover с кнопками yes/no. Это поповер запускается с помощью кнопки («pobtn»), который живет в строке в таблице в представлении:Является ли [мое использование] реакцией-бутстрапом «реагировать»?

+- View ---------------------+   +- View ---------------------+ 
| +- Table ----------------+ | click | +- Table ----------------+ | 
| | +- Row --------------+ | | --> | | +- Row --------------+ | | 
| | | ...    | | | pobtn | | | ...    | | | 
| | +--------------------+ | |   | | +--------------------+ | | 
| | +- Row --------------+ | | ,--------. +- Row --------------+ | | 
| | | ...  [pobtn] | | | | Yes/No |>| ...  [pobtn] | | | 
| | +--------------------+ | | `--------' +--------------------+ | | 
| | +- Row --------------+ | |   | | +- Row --------------+ | | 
| | | ...    | | |   | | | ...    | | | 
| | +--------------------+ | |   | | +--------------------+ | | 
| | ...     | |   | | ...     | | 
| +------------------------+ |   | +------------------------+ | 
+----------------------------+   +----------------------------+ 

The View, Стол и Роу являются все компоненты. Табличные данные извлекаются в представлении и помещаются в таблицу через реквизиты, и это стекает вниз в строку, что, я понимаю, является «правильным способом» для этого и имеет смысл. Там не так много местного штата.

Проблема связана с popover. «Правильно», чтобы сделать это, похоже, будет включать компонент Поповера вдоль каждой кнопки и нажимать реквизиты вниз для скрытых/видимых, я думаю. Это не кажется очень большим, но ближе к правильному способу сделать это в моем сознании.

Однако реагировать-самозагрузки поповер (который я использовал, потому что время), кажется, не работает таким образом:

var content = <MyRowPopoverContent/>; 
<OverlayTrigger trigger='click' placement='left' overlay={<Popover>{content}</Popover> 
    <button className="btn btn-primary small"><i className="fa fa-trash-o"></i> Delete</button> 
</OverlayTrigger> 

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

this.handleNoClick: function(){ 
    // Re-click the button to close; gross. 
    $('[data-row-id="'+this.props.row.key+'"]').find('.fa-trash-o').parents('button').first().click(); 
}, 
this.handleYesClick: function(){ 
    // Do stuff...update store which would re-render the view. 
    // Re-click the button to close; gross. 
    $('[data-row-id="'+this.props.row.key+'"]').find('.fa-trash-o').parents('button').first().click(); 
}, 
this.render: function(){ 
    <div> 
    <div>Are you sure?</div> 
    <input placeholder="Reason"/> 
    <button onClick={this.handleYesClick}>Yes</button> <button onClick={this.handleNoClick}>No</button> 
    </div> 
} 

Я приступил к реализации функции handleYesClick, пытаясь сделать обработку ошибок, асинхронные события и т.д., и все это кажется очень отрывочны, или, по крайней мере, хрупкий. Я предполагаю, что вопрос: мне нужен интерактивный popover, как мне это сделать? Похоже, что всплывающее окно будет частью локального состояния кнопки или строки, или, может быть, это ползет вверх, как кажется большинству вещей.

Поскольку реакция-бутстрап уже обеспечивает один, было бы неплохо использовать это, но я не уверен, как «подключить его» со всем остальным.

Обновление: Если бы это был простой статический поп, который был бы торт; показывая/скрывая его через реквизит, и нажатие pobtn довольно тривиально. Часть, с которой я сталкиваюсь, - это интерактивный контент внутри popover - имея do что-то (например, событие для обновления магазина), покажите spinner, определите, что-то работает, покажите сообщение об ошибке или исчезните. Даже нажав на кнопку «Нет» и сделать поповер исчезают не ясно (я в настоящее время найти его с JQuery и .click() кнопку еще раз.) Выполнение что все через реквизита от родителя кажется страшно ...

+0

Вместо того чтобы иметь всю логику в popover, вы могли бы вместо этого сохранить логику внутри компонентов более высокого уровня и передать обратные вызовы, которые затем кнопки будут звонить при нажатии? – badAdviceGuy

+0

Перечитайте свой вопрос и предложите альтернативу ниже. Способ Реагирования - это дети без гражданства, но если вы чувствуете, что родители становятся слишком толстыми с логикой, вы можете подтолкнуть логику к дереву. Это компромисс между инкапсуляцией и безгражданством. – akarve

ответ

1

Пусть вы инкапсулируете свой popover в компонент PopoverMenu. Вот Реагировать дружественный шаблон, где родитель обрабатывает события своего ребенка:

var Table = React.createClass({ 
    handlePopoverClick(selection, meta) { 
    // selection - the selection ('Yes' or 'No' in your case) 
    // meta - anything you want to know about the caller 
    }, 
    render: function() { 
    var open = /* boolean logic to determine if popover is open or closed* /; 
    // key idea is to pass the child a handler from the parent 
    <PopoverMenu handler={this.handlePopoverClick} open={open} ... /> 
    ... 
    } 
}); 

var PopoverMenu = React.createClass({ 
    handleClick: function(selection, meta) { 
    this.props.handler(selection, meta); 
    }, 
    render: function() { 
    ... 
    //somewhere you render the 'Yes' Button of this popover 
    <Button onClick={this.handleClick.bind(this, 'Yes', {row: 2})} /> 
    } 
}); 

PopoverMenu компонент является лицом без гражданства; он знает достаточно, чтобы сделать. Его обработчик получает событие щелчка, а затем при необходимости настраивает реквизиты PopoverMenu. Магия находится в .bind, что позволяет вам вводить специфическую для вызывающего пользователя информацию для обработчика, с которой нужно реагировать. (Вы можете себе представить, что .bind встречается в вызове map, где Yes и {row :2} - это динамические переменные.) Обратите внимание, что вы можете обрабатывать все варианты popover с помощью одного обработчика в родительском объекте и легко отслеживать его как часть состояния родителя (напримерRow), состояние ожидания/успеха/отказа любых вызовов. Это может показаться страшным, но логика должна жить где-то :) и лучше, если это где-то не ребенок, так как метод React - это дети без гражданства. Государство, естественно, становится реквизитом, поскольку информация перетекает от родителя к ребенку.

При этом, если ваш родитель делает слишком много бухгалтерского учета, и вы не получаете чистое, автономное поведение от дочерних компонентов, вы можете вывести логику в детей, как правило, за счет повторного использования детей , Для ребенка разумно и возможно управлять своим состоянием открытого/закрытого состояния и ожидания/ошибки/успеха. Если вы идете по этому маршруту, один шаблон, который вы можете использовать, - это поставить ребенка в состояние ожидания до тех пор, пока вы не получите соответствующее значение от родителя через реквизит. Например, если пользователь делает выбор в меню «X», что требует обратного вызова, ребенок делает setState{ selection: 'X'} и ждет родитель, чтобы подтвердить с помощью реквизита (которые отражают состояние магазина):

if (this.state.selection !== this.props.selection) { 
    //render component as waiting 
} else { 
    //render as normal 
} 

по вопросу о месторасположении открыть/закрыть статус popover, было бы проще, если бы вместо этого вы использовали компонент, такой как ButtonDropdown, который управляет собственным состоянием открытия/закрытия. (Возможно, вам придется установить пустой обработчик onSelect, чтобы он автоматически закрывался при выборе.)

Смежные вопросы