Подтвердить что ты не робот

Использование плагинов 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">&nbsp;</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? Или они принципиально нарушают предположения Реакта и не могут с ним работать?

4b9b3361

Ответ 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 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 и использовался для поддержания согласованности во всем приложении... Вы можете имеют аналогичную дилемму

Если, в отличие от меня, вам не повезло, что ваш компонент не имеет метода обновления, и вы не можете его создать, возможно, пришло время полностью пересмотреть подход