1

背景:我目前的 Meteor-React 项目是一个教学应用程序,教师可以远程观察学习者在做什么。学习者可以使用许多不同的视图,因此我需要将数据共享方面与视图本身分开。相同的视图将显示在教师的设备上,显示由学生的动作控制。

问题: * 我使用的技术是声音吗?* 当组件的输入没有改变时,如何防止组件被重新渲染?

详细信息:我创建了一个简单的原型(见下文)。这使用 Source 实例(在应用程序本身中将通过 MongoDB 集合更新)为视图组件提供反应性数据。在我的原型中,我只是生成随机数据。

我有两个惊喜。

一:我发现如果我.get()在源中调用 ReactiveVar,这足以触发 Tracker 对象读取新值,即使我返回一个完全非反应变量的值。正如所料,如果 ReactiveVar 的值没有改变,那么 Tracker 会忽略对非反应变量的任何改变。

二:Tracker获取的值转发给组件props`导致即使值不变也会s重新渲染。

代码:

import React, { Component } from 'react'
import { ReactiveVar } from 'meteor/reactive-var'
import { withTracker } from 'meteor/react-meteor-data'


/// SOURCE ——————————————————————————————————————————————————————————

class Source {
  constructor() {
    this.updateData = this.updateData.bind(this)
    this.updateData()
  }

  updateData() {
    const reactive = Math.floor(Math.random() * 1.25) // 4 times as many 0s as 1s
    data.set(reactive)
    console.log("reactive:", reactive)

    this.usable = ["a", "b", "c"][Math.floor(Math.random() * 3)]
    console.log("usable:  ", this.usable)

    setTimeout(this.updateData, 1000)
  }

  get() {       
    data.get() // We MUST get a reactive value to trigger Tracker...
    return this.usable // ... but we CAN return a non-reactive value
  }
}


let data = new ReactiveVar(0)
const source = new Source()


/// COMPONENT ———————————————————————————————————————————————————————

class Test extends Component{

  render() {
    console.log("rendered:", this.props.data)

    return (
      <div>
        {this.props.data}
      </div>
    )
  }
}

export default withTracker(() => {
  const data = source.get()
  console.log("UPDATE:  ", data)
  console.log("")

  const props = {
    data
  }

  return props
})(Test)

示例控制台输出,带有注释:

reactive: 1
usable:   b
UPDATE:   b

rendered: b <<< initial value rendered
reactive: 1 <<< no change to reactive value...
usable:   a <<< ...so usable value is ignored
reactive: 0 <<< reactive value changes...
usable:   c <<< ... so an update is sent to the component
UPDATE:   c

rendered: c <<< c rendered
reactive: 0 <<< no change to the reactive value...
usable:   c
reactive: 0
usable:   b
reactive: 0
usable:   c
reactive: 0
usable:   b
reactive: 1 <<< but when reactive value changes
usable:   c <<< the usable value does not
UPDATE:   c

rendered: c <<< c re-rendered, although unchanged

回顾一下:我的计划是每次从学生那里收到新数据时,在我的 Source 实例中增加一个 ReactiveVar。但是,如果学生只是移动光标,那么我只希望显示学生光标的组件重新渲染,而不是整个视图。

对于如何优雅地实现这一目标,我将不胜感激。

4

1 回答 1

0

您所看到的行为是 Meteor 的“魔法”的一部分——它看到您的反应变量依赖于一个普通变量,并且也使该变量具有反应性,或者更准确地说,它在其上设置了一个监视。

withTracker 经常会触发多个渲染,所以优化这些的最好方法是使用 React.memo()

我个人不喜欢 React.memo,感觉很笨拙,并且让开发人员做一些不必要的工作。这里有一篇很好的文章解释了它:

https://dmitripavlutin.com/use-react-memo-wisely/

当一个组件被包裹在 React.memo() 中时,React 会渲染该组件并记住结果。在下一次渲染之前,如果新的 props 相同,React 会重复使用记忆的结果,跳过下一次渲染。

于 2020-04-12T23:03:21.397 回答