温馨提示:本文翻译自stackoverflow.com,查看原文请点击:javascript - Using React components inside KnockoutJS
javascript knockout.js reactjs

javascript - 在KnockoutJS中使用React组件

发布于 2020-05-08 19:16:34

我们有一个大型的Web应用程序,主要使用KnockoutJS构建。我正在研究是否有可能迁移到React,但是这种方式需要重写整个应用程序。我的想法是使用一种自下而上的方法:首先将基本构建块一一替换。

我受到一些先前工作的启发,可以在KnockoutJS绑定处理程序中调用ReactDOM.render:

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

Knockout有其自己的依赖项跟踪系统,因此每当某些数据更改时,它将调用update方法。

它运行完美,并且重新渲染了组件以反映对数据的任何更改。但是,当在React事件处理程序中更新数据时,它会崩溃。例如,此组件无法正常工作:

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

注意:在这种情况下,value是一个ko.observable,并且像在事件处理程序中一样调用它会导致bindingBindingHandler的update方法被调用,而后者又会调用ReactDOM.render。但是,此渲染仅工作一次,之后组件停止更新。

此问题已在此CodePen中演示单击该框,然后尝试键入一些内容。然后进行一次更新,然后停止调用组件的功能。

编辑:我相信问题是对ReactDOM.render的第二次调用(当用户在onChange处理程序中更新值时)不是同步的。这意味着淘汰赛的依赖关系检测无法正常工作,任何后续调用都不再调用绑定处理程序的update方法。

可以以某种方式规避吗?

查看更多

提问者
waxwing
被浏览
46
waxwing 2020-02-25 23:34

如我所料,问题似乎是ReactDOM.render在某些情况下是异步的-在这种情况下,是从React中的事件处理程序调用时。

这意味着,如果您在更新方法本身中取消引用了您依赖的任何可观察对象,则Knockout的依赖项跟踪机制将按预期工作。这就是Gawel1908提出的修改使其起作用的原因-不是因为值被“重置”,而是因为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)}/>;
}

更新,可工作的Codepen。