如何避免在简单的className更改中重新呈现整个树?

时间:2015-07-21 22:54:07

标签: javascript svg reactjs

我有一些嵌套的React组件,其内部是一个大svg图,其中包含数百个linerect个元素。为了启用某些应用程序范围的行为和外观更改,我想更改最上面组件的className。问题是,如果我这样做,整个应用程序会重新呈现。

我理解这种行为在单向渲染流的意义上是有意的,但我认为React会更聪明地重用它并将DOM更改保持在最低限度。

此处的最小示例:https://jsbin.com/rabofewawu/1/edit?html,js,output 如您所见,每次按“此处”时SVG中的线条图案都会发生变化,但我只想更改背景颜色。

当我尝试通过更改内部svg元素的transform属性来缩放和平移g时,会出现类似但更极端的示例。使用d3,我只需更改属性。使用react,我的render函数被调用,更新后的状态会生成更新的transform属性,整个组将从头开始重新渲染,而不是更改DOM属性。

我错过了什么吗?什么是React方式来实现我想要做的事情?

2 个答案:

答案 0 :(得分:2)

您可以使用组件的shouldComponentUpdate功能来控制它。默认情况下,它始终返回true(因此组件将始终重新呈现)。

这里有一些关于此功能的文档https://facebook.github.io/react/docs/component-specs.html#updating-shouldcomponentupdate

答案 1 :(得分:2)

采用这种简单无害的渲染功能:

render(){
    return <div>{Date.now()}</div>;
}

在React的心智模型中,这将始终显示每毫秒的当前数字。 React概念上每秒更新无限次。渲染的输入在这里是世界上的一切,但我们碰巧只是使用时钟。给定相同的世界,我们从渲染中获得相同的输出,因此它是幂等的。

好的废话......我们没有无限快速的计算机,所以我们需要妥协。而不是渲染的输入是我们将其限制为状态和道具(和上下文)的所有内容。

在此限制设置中,使用Math.random或Date.now会破坏规则。如果你需要使用这些的输出,它必须首先通过状态或道具。这看起来怎么样?那么我们可以使用确定性随机数生成器并将种子存储在状态中。这是modified version of your component做到这一点:

var MyComponent = React.createClass({
  displayName:"MyComponent",

  getInitialState(){
    return {
      seed: Math.floor(Math.random()*0xffffff)
    };
  },

  render: function() {
    // make a random number generator with the given seed
    var rng = new Chance(this.state.seed);
    function random(x){
      return rng.floating({min: 0, max: x, fixed: 7})
    }

    var s=100, lines = [];

    for (var i=0; i<100; i++) {
      var line = { x1: random(s), y1: random(s), x2: random(s), y2: random(s) };

      lines.push(React.createElement("line", line));
    }

    return React.createElement("svg", { height: s, width: s}, lines);
  }
});

每秒渲染少于无限次,并且仅渲染某些组件是一种优化。优化不应该影响程序的行为。

如果您想要不同的随机数,可以将种子设置为不同的随机数。在这里使用真实Math.random()是可以的,因为状态是代码中的结果或i / o操作,并且您在响应其他一些i / o(例如点击处理程序)时调用此setState。

时间相似;如果要渲染当前时间,请使用setTimeout和setState以及当前时间。然后,您可以在渲染中显示它的喜好,包括将其传递给其他组件并对其进行任何类型的数学运算。