我一直在努力解决这个问题很长一段时间,但未找到任何答案。
我使用 react-meteor-data 来管理我的数据,并在我的流星应用程序中做出反应。在处理mongo的数据时工作正常,但我不能让它与道具反应。
在 App.js 中,我调用了我想要反应的容器,并在App状态发生变化时重新呈现。
<MyContainer someState={this.state.MyState} />
在 MyContainer.js 中,我有一个来自 react-meteor-data 的<{1}}
createContainer
第一次渲染组件时,此工作正常,export default createContainer(params => {
Meteor.subscribe('someCollection');
return {
someCollection: SomeCollection.find({}).fetch(),
stateFromParent: params.someState
};
}, MyContainer);
正确获取MyContainer
。
问题是,当MyState
从MyState
发生变化时,我可以在Chrome Dev React工具中看到它确实已更新为App
(createContainer
有一个具有正确更新状态的prop)但ReactMeteorDataComponent
函数未运行,因此createContainer
不会更新props
。
因此,MyContainer
从props
更新,但不会更新ReactMeteorDataComponent
无限期保留数据。它就像MyContainer
并不认为其道具的更新有变化,因此不会运行其功能。
我真的觉得我错过了一些东西,因为这似乎是非常基本的东西,谢谢你的帮助。
答案 0 :(得分:0)
它使用meteor的Tracker在计算失效时自动更新包装组件(即,当其中一个反应数据源(如反应变量,订阅句柄或获取的MiniMongo游标)具有新值时)。要了解有关Tracker的更多信息,请参阅Tracker manual。这是一个深入的资源,无需了解基础知识的工作原理。
它的实现方式与您在Meteor中通常接近反应性跟踪的方式不同,因为每当容器的道具发生变化时,它也需要重新运行计算。
源代码不是很长或很复杂,可以在GitHub上找到(目前here)。
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();
}
})
每当计算失效(并因此重新运行)时,它就会停止计算并强制重新呈现容器,这将重新创建新计算并获得更新的数据。
这里是高级容器功能(为简洁起见,删除了一些部分):
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)
},
};
要点是:
- 在安装之前,会创建一个新的数据管理器(1)
。它负责运行计算并根据数据更改填充this.data
。
- 首先,每当组件更新时,计算运行(2)
,数据更新(3)
。只要组件接收到新状态或道具(在这种类型的容器中,它应该只是道具),就会发生更新,并且正如我们之前看到的那样,当跟踪器计算失效时,由于调用了component.forceUpdate()
包裹的组件接收父级的道具,以及跟踪器计算的数据为props
:
return <WrappedComponent {...this.props} {...this.data} />;
react-meteor-data
在流星指南中有short section。
通常,指南中的简单示例(以及OP的示例)应该可以正常工作,只要使用setState()
正确设置状态(请参阅“它是如何工作的?”部分上文)。
此外,没有必要将容器状态重新映射到发送给孩子的道具,因为它们被传递(除非有充分的理由这样做)。
如果遇到任何性能问题,请考虑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);
在此示例中,请注意容器需要id
道具,并且它也可用于包装组件,以及loading
,list
等(其中)来自容器在示例中的计算。)