当前,我正在尝试使用功能性StateLess组件,因为对于StoryStor来说,它们似乎更容易测试/模拟/分开。
我已经开始使用withTracker以便将React组件与Meteor集成在一起,并且在使用Meteor.subscribe时一切正常,例如:
...
module.exports = withTracker( (props) => {
subscription = Meteor.subscribe( 'posts' )
loading = subscription.ready()
posts = Posts.find({}).fetch()
return {loading, posts}
} )( LowerLevelComponent )
...
但是有时候我需要使用Meteor.call使它成为Reactive,
...
module.exports = withTracker( (props) => {
feed = new ReactiveVar(null)
Meteor.call( 'feed', (error, response) => {
work = // do some work
feed.set( work )
} )
loading = subscription.ready()
feed = feed.get()
return {loading, feed}
} )( LowerLevelComponent )
...
这里的问题是,每次此组件运行时,都会将变量“ feed”再次分配给ReactiveVar,然后再次调用Meteor.call,并开始无限循环。
我发现的唯一解决方案是使用“提要”作为功能组件中的ReactiveVar,例如:
feed = new ReactiveVar(null)
module.exports = withTracker( (props) => {
if( feed.get() == null ) {
Meteor.call( 'feed', (error, response) => {
work = // do some work
feed.set( work )
} )
}
loading = subscription.ready()
feed = feed.get()
return {loading, feed}
} )( LowerLevelComponent )
这里出现的问题是:
如果我浏览路由器,然后返回此页面,该值仍将填充ReactiveVar或withTracker确保它已从内存中销毁了怎么办?
如果我想拥有两个这样的组件但加载不同的提要怎么办?我是否必须为范围之外的变量使用“动态”名称?这似乎很hacky。我看到有些人使用Session
来存储这些东西,但这听起来更加骇人听闻。
理想情况下,我会将ReactiveVar / Meteor.call逻辑存储在什么地方,并使它仍然属于我组件的特定实例?
这是“状态”的全部内容,我应该使用一些React组件让我setState吗?从我糟糕的React经验来看,最好不要使用状态,因此可以在StoryBook / Jest /任何需要使用的测试框架上轻松地测试代码?
通过查看源代码实现here,我可以看到它将this.props和this.data发送到较低级组件。this.data是技巧吗?是我应该添加我的ReactiveVar的地方,以便我可以对其进行跟踪并仍然对该实例保持唯一性吗?
阅读@Fred Stark回复后:
因此,这里的主要问题是通过使用reactVar,您正在向组件引入状态。这使功能性无状态组件成为表示您要执行的操作的错误模式选择。在这种情况下,尝试将类模式与React.Component一起使用
我得出的结论是, 的主要问题不是我正在向组件引入状态,但实际上,这里的主要问题是Meteor.call的方式()的行为与Meteor.subscribe()的行为不同。
如果将“状态添加到函数无状态对象”是一个实际问题,那么withTracker
函数将完全没有意义。 Meteor.subscribe()确实向FSC添加了状态,这是在Meteor Guide
得出该结论后,我在网上进行了更多搜索,并意识到有一些尝试解决此问题的实现,例如meteor-call和ReactiveMethod。这些库的潜在功能将使我能够以“包含”方式隐藏变通方法,并使Meteor.call的工作方式与Meteor.subscribe()相似。
其他选择可能是不使用Meteor.call来获取数据,即使它不会是被动的,但我不确定这会产生哪些副作用。
答案 0 :(得分:0)
因此,经过几天的努力,我终于找到了一种解决方案,该解决方案不会破坏我要遵循的某些限制/规则,以使我的组件兼容并在我的网站上以及在故事书。
诀窍是创建一个不与withTracker一起使用的包装函数,而该函数将在发生反应性事件时保留此“非反应性”作用域,所有这些都具有以下优点:一旦将我的组件从屏幕上删除,便会“自动”创建(并希望!)并销毁它。
代替:
feed = new ReactiveVar(null)
module.exports = withTracker( (props) => {
if( feed.get() == null ) {
Meteor.call( 'feed', (error, response) => {
work = // do some work
feed.set( work )
} )
}
loading = subscription.ready()
feed = feed.get()
return {loading, feed}
} )( LowerLevelComponent )
我正在做:
module.exports = (props) => {
// NOTE: this will create a ReactiveVar everytime my HOC is created,
// without using withTracker.
feed = new ReactiveVar(null)
// The "reactive data" will live on my "Intermediary Order Object"
// which uses withTracker and will be reactive!
Intermediary = withTracker( (props) => {
if( feed.get() == null ) {
Meteor.call( 'feed', (error, response) => {
work = // do some work
feed.set( work )
} )
}
loading = subscription.ready()
feed = feed.get()
return {loading, feed}
} )( LowerLevelComponent )
<Intermediary {...props} />