【问题标题】:Getting infinite loop using cycle-idb with text field for input使用带有输入文本字段的循环 idb 获取无限循环
【发布时间】:2025-12-19 02:15:07
【问题描述】:

我一直在尝试创建一个简单的测试应用程序,该应用程序从文本字段中获取用户输入,显示它,并使用cycle-idb 将其持久化。但无论我做什么,我都会陷入无限循环。

这是整个主要功能:

function intent(domSources) {
  return domSources.select('.name')
    .events('input')
    .map(ev => ev.target.value);
};

function model(input$, db$) {
  const log$ = db$;
  return xs.combine(input$, log$)
    .map(([input, logs]) => {
      return {
        id: 1,
        name: input,
      }
    }).startWith({id: 1, name: ""});
};

function view(state$) {
  return state$.map(log => {
    return (
      <div>
        <label for='name'>Name: </label>
        <input 
          className='name' 
          type='text' 
          value={log.name}
          placeholder="Enter a log name"
        />
        <p>{log.name}</p>
      </div>
    )
  });
};

function persist(state$) {
  return state$.map(log => {
    return $put('logs', log)
  });
};

export function main (sources) {
  const db$ = sources.IDB.store('logs').getAll();
  const input$ = intent(sources.DOM);
  const state$ = model(input$, db$);
  const vtree$ = view(state$);
  const updateDb$ = persist(state$);

  return {
    DOM: vtree$,
    IDB: updateDb$,
  };
}

我正在尝试使用 MVI 并以 TodoMVC 为例,但我不知道如何在不创建无限循环的情况下管理循环依赖项。

任何建议或指向其他参考资料将不胜感激。

【问题讨论】:

  • 它应该不会有什么不同,但你可以尝试用sampleCombine 代替take(1)combine 吗?
  • 谢谢@JanvanBrügge,是的,可能不会,尽管我觉得我的问题确实涉及能够从数据库中获取一次更新,从那时起,只更新数据库,而不是另一个一路走来。
  • 编辑此内容以删除 take(1)... 错误版本的代码,这会停止无限循环,但会中断数据库更新

标签: javascript cyclejs


【解决方案1】:

不幸的是,first answer 导致数据库更新流中断。

在 gitter 中,@janat08 建议对 persist 函数进行以下更改,确实对我有用:

function persist(state$) {
  return state$.compose(dropRepeats((x, y) => {
    return x.id === y.id && x.name === y.name;
  })).map(log => {
    return $put('logs', log)
  });
};

尚未将此标记为解决方案,因此 Jan 有机会编辑他的解决方案,或者如果有人想出一个不那么 hacky 的解决方案。

【讨论】:

    【解决方案2】:

    解决方法是使用 dropRepeats 进行深度比较。

    来自 gitter 的指向“优化”解决方案的答案:

    function model(input$, db$) {
      return xs.merge(xs.never(), db$.take(1)).map(name => {
        return input$.startWith(name).map(name => {
          return { id: 1, name }
        })
      }).flatten()
    };
    

    【讨论】:

    • 不幸的是,这会在数据库中产生更多错误。首先,它将 name 属性初始化为一个空数组,但之后不会更新数据库。似乎take(1) 仍在终止流到数据库接收器,尽管这对我来说仍然没有意义。
    • 我目前最好的工作版本是:github.com/jgaehring/farmos-cycle/blob/master/src/app.jsx。根据您的建议,我在 persist 函数中使用 dropRepeats。你想用它来编辑你的答案以便我接受吗?你应该得到信用! :)
    • 在 take() 中添加了无限流,希望它不会终止,因为有一个特殊的符号会发生这种情况。
    • 还是同样的问题。 ://