Использование компонентов React внутри KnockoutJS - PullRequest
1 голос
/ 20 февраля 2020

У нас есть большое веб-приложение, в основном построенное с использованием Knockout JS. Я смотрю, есть ли возможность перейти на React, но таким способом, который требует переписывания всего приложения. Моя идея состояла в том, чтобы использовать подход «снизу вверх»: начните с замены базовых c строительных блоков по одному.

Я был вдохновлен некоторыми предыдущими работами , чтобы вызвать ReactDOM.render внутри обработчик привязки Knockout JS:

ko.bindingHandlers.react = {
    init() {
        return {controlsDescendantBindings: true};
    },
    update(element, valueAccessor) {
        const {component, props} = valueAccessor();
        ReactDOM.render(React.createElement(component, props), element);
    }
};

Knockout имеет собственную систему отслеживания зависимостей, поэтому он будет вызывать метод обновления при каждом изменении некоторых данных.

Он отлично работает, и компонент перерисовывается для отражения любых изменений данных. Однако он ломается, когда данные обновляются в обработчике событий React. Например, этот компонент не работает должным образом:

const Input = function ({value}) {
    return <input type="text" 
                  value={value()} 
                  onChange={e => value(e.target.value)}/>;
}

Примечание: значение в этом случае является ko.observable, и его вызов как в обработчике событий вызовет метод обновления bindingHandler, который в свою очередь вызывает ReactDOM.render. Однако этот рендеринг работает только один раз, после чего компонент прекращает обновление.

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

Редактирование: я считаю, что проблема заключается во втором вызове ReactDOM.render (когда значение обновляется пользователем в обработчике onChange) не синхронно. Это означает, что обнаружение зависимостей Knockout не может работать, и любые последующие вызовы больше не вызывают метод обновления обработчика привязки.

Можно ли это как-то обойти?

Ответы [ 2 ]

1 голос
/ 20 февраля 2020

У меня сработало:

 update(element, valueAccessor) {
    const {component, props} = valueAccessor();
    props.value(props.value());
    ReactDOM.render(React.createElement(component, props), element);
}

если вы переосмыслите sh свой observable, то это будет работать, но, к сожалению, я не знаю как.

0 голосов
/ 25 февраля 2020

Как я уже догадался, проблема в том, что ReactDOM.render в некоторых случаях асинхронный - в этом случае при вызове из обработчика событий в React.

Это означает, что если вы разыменовываете любые наблюдаемые, то вы В зависимости от метода обновления, механизм отслеживания зависимостей Knockout работает, как и ожидалось. Вот почему предложенная Gawel1908 модификация заставляет его работать - не потому, что значение «reset», а потому, что props.value разыменовано.

Я решил вместо этого использовать соглашение: всегда развертывать любые такие наблюдаемые в valueAccessor Само по себе:

<div data-bind="react: { component: Input, props: { value: val(), setValue: val }}">
</div>

И не разворачивайте его в компоненте:

const Input = function ({value, setValue}) {
  return <input 
           type="text" 
           value={value} 
           onChange={e => setValue(e.target.value)}/>;
}

Обновлен рабочий код.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...