当道具改变时,反应流星数据容器不会更新子节点

Syl*_*ier 5 meteor reactjs

我一直在努力解决这个问题很长一段时间,但未能找到任何答案.

我使用react-meteor-data来管理我的数据,并在我的流星应用程序中做出反应.处理mongo的数据时工作正常,但我不能让它与道具反应.

在这里,在App.js,我打电话给我的容器,我想反应和重新呈现在应用变化的状态.

<MyContainer someState={this.state.MyState} />
Run Code Online (Sandbox Code Playgroud)

MyContainer.js中,我有一个createContainer来自反应流星数据

export default createContainer(params => {
   Meteor.subscribe('someCollection');

   return {
      someCollection: SomeCollection.find({}).fetch(),
      stateFromParent: params.someState
   };
}, MyContainer);
Run Code Online (Sandbox Code Playgroud)

这在第一次渲染组件时工作正常,MyContainer正确获取MyState.

事情是,当MyStateApp改变时,我可以在Chrome Dev React工具中看到它确实已更新createContainer(ReactMeteorDataComponent具有正确更新状态的道具)但该createContainer功能未运行,因此props不更新MyContainer.

所以这些props是从谁更新,ReactMeteorDataComponent而不是MyContainer由谁无限期地保存数据.它就像createContainer不考虑其prop的更新有变化,因此不运行其功能.

我真的觉得我错过了一些东西,因为这似乎是非常基本的东西,谢谢你的帮助.

Mas*_*rAM 1

OP 没有提到状态是如何改变的,所以原来的例子是不完整的。因此,我将尝试解释容器创建的原理,希望对理解它有所帮助。


它是如何工作的?

当其计算无效时(即,当反应性数据源之一,例如反应性变量、订阅句柄或获取的 MiniMongo 游标具有新值时),它使用 Meteor 的 Tracker 自动更新包装的组件。要了解有关 Tracker 的更多信息,请参阅Tracker 手册。这是一个深入的资源,不需要了解基础知识的工作原理。

它的执行方式与您通常在 Meteor 中进行反应性跟踪的方式不同,因为每当容器的 props 发生更改时,它也需要重新运行计算。

源代码不是很长或很复杂,可以在 GitHub 上找到(目前在这里)。

  Tracker.autorun((c) => {
    if (c.firstRun) {
      //...
        data = component.getMeteorData();

    } else {
      // Stop this computation instead of using the re-run.
      // We use a brand-new autorun for each call to getMeteorData
      // to capture dependencies on any reactive data sources that
      // are accessed.  The reason we can't use a single autorun
      // for the lifetime of the component is that Tracker only
      // re-runs autoruns at flush time, while we need to be able to
      // re-call getMeteorData synchronously whenever we want, e.g.
      // from componentWillUpdate.
      c.stop();
      // Calling forceUpdate() triggers componentWillUpdate which
      // recalculates getMeteorData() and re-renders the component.
      component.forceUpdate();
    }
  })
Run Code Online (Sandbox Code Playgroud)

每当计算无效(并因此重新运行)时,它就会停止计算并强制重新渲染容器,这将重新创建新的计算并具有更新的数据。

高级容器功能在这里(为简洁起见,删除了一些部分):

export const ReactMeteorData = {
  componentWillMount() {
    this.data = {};
    this._meteorDataManager = new MeteorDataManager(this); // (1)
    const newData = this._meteorDataManager.calculateData(); // (2)
    this._meteorDataManager.updateData(newData); // (3)
  },

  componentWillUpdate(nextProps, nextState) {
    // backup current state and props, assign next ones to components
    let newData = this._meteorDataManager.calculateData(); // (2)
    this._meteorDataManager.updateData(newData); // (3)
    // restore backed up data
  },

  componentWillUnmount() {
    this._meteorDataManager.dispose(); // (4)
  },
};
Run Code Online (Sandbox Code Playgroud)

要点是: - 在安装之前,创建一个新的数据管理器(1)。它负责运行计算并this.data根据数据变化进行填充。- 首先,每当组件应该更新时,就会运行计算(2)并更新数据(3)。每当组件接收到新的状态或属性(在这种类型的容器中,它应该只是属性)时,就会发生更新,并且,正如我们之前所看到的,当 Tracker 计算由于调用component.forceUpdate().

包装的组件接收父级的 props,以及 Tracker 计算的数据,如下所示props

return <WrappedComponent {...this.props} {...this.data} />;
Run Code Online (Sandbox Code Playgroud)

关于如何使用它还有更多要点吗?

流星指南中有react-meteor-data一个简短的部分。

一般来说,指南中的简单示例(以及OP的示例)应该可以正常工作,只要使用(请参阅setState()上面的“它是如何工作的?”部分)适当设置状态即可。

此外,无需将容器状态重新映射到发送给子级的 props,因为它们会被传递(除非有充分的理由这样做)。

preventing re-renders如果您遇到任何性能问题,请考虑本节中的要点。

来自指南:

export default ListPageContainer = withTracker(({ id }) => {
  const handle = Meteor.subscribe('todos.inList', id);
  const loading = !handle.ready();
  const list = Lists.findOne(id);
  const listExists = !loading && !!list;
  return {
    loading,
    list,
    listExists,
    todos: listExists ? list.todos().fetch() : [],
  };
})(ListPage);
Run Code Online (Sandbox Code Playgroud)

在此示例中,请注意容器需要一个idprop,并且它也将可供包装组件以及loadinglist等(来自示例中容器的计算)。