Использование плагинов JQuery, которые преобразуют DOM в React Components?
Некоторые плагины JQuery не просто добавляют поведение к узлам DOM, но меняют их. Например, Bootstrap Switch включает
<input type="checkbox" name="my-checkbox" checked>
во что-то вроде
<div class="bootstrap-switch bootstrap-switch-wrapper bootstrap-switch-on bootstrap-switch-large bootstrap-switch-animate">
<div class="bootstrap-switch-container">
<span class="bootstrap-switch-handle-on bootstrap-switch-primary">ON</span>
<label class="bootstrap-switch-label"> </label>
<span class="bootstrap-switch-handle-off bootstrap-switch-default">OFF</span>
<input type="checkbox" name="download-version" checked="" data-size="large" data-on-text="3" data-off-text="2.0.1">
</div>
</div>
с
$("[name='my-checkbox']").bootstrapSwitch();
Который не сдерживает реакцию:
Uncaught Error: Invariant Violation: findComponentRoot(..., .0): Unable to find
element. This probably means the DOM was unexpectedly mutated (e.g., by the
browser), usually due to forgetting a <tbody> when using tables or nesting <p> or
<a> tags. ...<omitted>...`.
Есть ли рекомендуемый метод включения этих плагинов в компоненты React? Или они принципиально нарушают предположения Реакта и не могут с ним работать?
Ответы
Ответ 1
Нет, реакция будет реагировать (ха-ха) плохо на что-либо, что изменяет собственную структуру компонента компонента вне реакции. Это то, чего вы никогда не хотите делать. Рекомендуемым решением будет копирование функциональности того, что вы пытаетесь сделать с jquery или аналогичным плагином, в ответ.
Сказав это, существует разумный способ сделать это для конкретных случаев, когда вы просто не можете обойтись без него, но по сути это означает, что внутри реагирует некорректная внутренняя реакция.
Пример:
var Example = React.createClass({
componentDidMount: function() {
var $checkboxContainer = $(this.refs.checkboxContainer.getDOMNode());
var $checkbox = $('<input />').prop('type', 'checkbox');
$checkboxContainer.append($checkbox);
$checkbox.bootstrapSwitch({});
},
render: function() {
return (
<div>
<div ref="checkboxContainer"></div>
</div>
)
}
});
Теперь, конечно, вы представляете компонент с вложенным div. Вложенные при установке в dom в первый раз, когда вложенный div получит флажок, добавленный к нему jquery, который затем также выполнит наш плагин jquery.
Этот конкретный примерный компонент имеет мало смысла для него, однако вы можете видеть, как это может интегрироваться в более сложный компонент, позволяя при этом повторно отображать и реагировать на изменения состояния и т.д. Вы просто теряете способность напрямую реагировать на события/изменять вещи внутри указанного флажка, который, насколько реагирует, не существует.
Теперь с приведенным выше примером, если у вас должна быть какая-то реакционная логика для добавления/удаления вложенного div, вам придется иметь ту же логику, что и вставляемый div, ответственный за повторную установку флажка и повторную инициализацию это с плагином jquery. Однако поскольку реакция только модифицирует dom, когда это необходимо, этот вставленный dom-контент не будет удален, если вы не сделаете что-то, что модифицирует контейнер div таким образом, чтобы он был удален/повторно отображен в dom. Это означает, что вы все равно можете получить доступ ко всем событиям внутри реакции для этого контейнера div и т.д.
Вы также можете использовать функцию componentDidMount
, чтобы реагировать на привязку событий или обратных вызовов к определенным взаимодействиям в самом флажке. Просто убедитесь, что они правильно отвязали их в componentWillUnmount
или везде, где это имеет смысл сделать это в жизненном цикле компонента в вашем конкретном случае.
Ответ 2
В этом великом учебнике по ryanflorence вы получите представление о том, как это сделать:
Методика
- DOM libs обычно управляют DOM
- Реакция пытается повторно отобразить и найти другой DOM, чем в прошлый раз, и freaks out
- Мы скрываем DOM манипуляции с React, разбив дерево рендеринга, а затем пересоединение вокруг DOM, которым манипулирует lib.
- Потребители наших компонент может оставаться в Реактировании.
Ответ 3
Конечно, есть такая техника. Мы все это делаем все время.
- Вы создаете компонент React для переноса плагина jQuery.
- Внутри вашего
render()
вы возвращаете пустой <div ref="placeholder" />
- В вашем методе componentDidMount вы извлекаете этот элемент по его ref и инициализируете свой плагин jQuery.
- В
componentWillUnmount
вы очищаете его. Вызов "уничтожить" или что-то еще, чтобы избежать утечек памяти.
Что это. К счастью, полностью безопасно модифицировать DOM таким образом в React.
Если вы хотите, чтобы этот плагин реагировал на изменения реквизита, все становится немного сложнее. Вам необходимо переопределить другие методы жизненного цикла, например componentWillReceiveProps
, проверить, когда реквизит действительно изменился, и вызвать соответствующие методы плагина. Я могу объяснить более подробно, если у вас появятся конкретные вопросы, общая тема слишком широка для комментария.
Ответ 4
Это скорее философский вопрос
Реакция была создана для оптимизации манипуляций с DOM и имеет много проводников за кулисами, чтобы сделать это, когда состояние компонента изменяется через setState
Это приведет к тому, что упомянутая проводка пройдет через свою виртуальную DOM, чтобы найти узлы, которые необходимо обновить.
Если вы должны использовать React, чтобы попытаться сохранить уровень согласованности в вашей кодировке, лучше всего применить JQuery DOM-манипуляцию внутри компонента componentDidMount так, чтобы...
componentDidMount(){
this.node = $("#"+this.props.id); // Keep a reference to the node
this.chart = this.node.easyPieChart(); // Apply JQuery transformation and keep a reference
this.percentTitle = this.chart.find(".percent"); // Keep a reference to the title
}
Сделав это, независимо от вашего метода "refresh", НЕ делайте никаких вызовов setState, вместо этого вызывайте любой метод обновления, который может иметь ваш компонент JQuery, например...
componentWillMount(){
this.interval = setInterval(this._doRefresh.bind(this), 1500);
}
_doRefresh( percentage ){
// Note how setState is NOT being called here
percentage = percentage || Math.floor (Math.random() * 100) // simulate since we're not getting it yet
this.chart.data('easyPieChart').update(percentage); // call easyPieChart update
this.percentTitle.text(percentage);
}
В этот момент, если вы спрашиваете, зачем использовать React вообще, ну, в моем случае этот компонент является элементом в списке других компонентов React и использовался для поддержания согласованности во всем приложении... Вы можете имеют аналогичную дилемму
Если, в отличие от меня, вам не повезло, что ваш компонент не имеет метода обновления, и вы не можете его создать, возможно, пришло время полностью пересмотреть подход