【问题标题】:React re-render via setState vs direct DOM manipulation?通过 setState 与直接 DOM 操作反应重新渲染?
【发布时间】:2018-03-16 04:51:36
【问题描述】:

我已经使用 react 大约 6 个月了,一直困扰我的是重新渲染的工作方式。

下面是一个传统的组件,它有一个输入框并将数据发送到服务器,其值被一些其他表单使用,以及多个几乎静态的 HTML 元素,这些元素从不使用或很少更改。我说的很少,因为静态元素可以构建并存储在componentWillMount() 方法中的变量中。但如果这个问题不止于此,render 应该包含对buildComplexHTMLFromData 方法的调用。

buildComplexHTMLFromData = (data) => {
  // Lot of javascript to build the boxes based on the initial or data 
  // that changes so rarely
  // array.map.filter.find etc.
  return (
    <div>
      //Complex HTML element 1
      //Complex HTML element 2
      //....
      //....
      //Complex HTML element n      
    </div>
  )
}

sendDataToBackend = (event) => {
  this.setState(
    { value: event.target.value },
    () => this.functionThatSendsDataToBackend()
  )
}

render() {
  <div>
    // Active input that sends data to the backend
    <input 
      value={this.state.value} 
      onChange={this.sendDataToBackend} 
    />
    {this.buildComplexHTMLFromData()}    
  </div>
}

现在在输入框更改时设置状态甚至会触发 buildComplexHTMLFromData 方法,该方法会再次执行复杂的 javascript。我听说 React 通过区分 DOM 来有效地重新渲染做了一些聪明的事情,但是这个 javascript 无论如何都会执行。

另一方面,使用两种sendDataToBackend 方法可以实现相同的功能,如下面的sn-p 所示。然而,这确保了只有目标输入元素被更改,而不会触及已经呈现的元素或在 buildComplexHTMLFromData 方法上执行任何 javascript。

buildComplexHTMLFromData = (data) => {
  // Lot of javascript to build the boxes based on the initial or data 
  // that changes so rarely
  // array.map.filter.find etc.
  return (
    <div>
      //Complex input box 1
      //Complex input box 2
      //....
      //....
      //Complex input box n      
    </div>
  )
}

sendDataToBackend = (event) => {
  //First strategy
  var element = document.getElementById("persistable-input");
  element && element.value = event.target.value

  //Second strategy
  this.persistableInput.value = event.target.value
}

render() {
  <div>
    // Active input that sends data to the backend or for other forms
    <input 
      id="persistable-input"
      ref={(elem) => { this.persistableInput = elem }}
      value={this.state.value} 
      onChange={this.props.persistedValue} 
    />
    {this.buildComplexHTMLFromData()}    
  </div>
}

我不知道我是否遗漏了某些东西,或者这对性能的影响是否很小,但我觉得对于复杂的组件来说可能会很费力。我查看了多篇关于 React 的协调范式的文章,但似乎没有解决这个问题。

如果有人能对 React 的这一领域有所了解,我将不胜感激,因为我正在寻找一些关于在大多数情况下在 React 中进行性能协调的很酷的提示和输入。

提前致谢。

【问题讨论】:

  • React 不使用 shadow DOM 而不是直接操作 DOM?
  • Shadow DOM 与否,普通的 DOM 操作不会重新渲染所有非目标元素,对吧?树中只会修改目标元素。

标签: javascript reactjs dom-manipulation


【解决方案1】:

这正是创建 shouldComponentUpdate 生命周期挂钩的目的。如果你知道你的组件不应该总是重新渲染,那么你可以添加这个生命周期钩子来检测哪个状态正在改变。如果你不关心它,你可以return false 并且buildComplexHTMLFromData 函数永远不会运行。

编辑:

他们还公开了一个名为 PureComponent 的基类,它在后台为您处理 shouldComponentUpdate。

【讨论】:

  • shouldComponentUpdate 将决定在哪里必须再次调用render() 方法,这里需要更新输入框的值。然而,render 方法也具有渲染所有其他复杂 HTML 元素的逻辑。由于它是一种方法,即使更新不是目标,复杂的 javascript 也一定会运行。 PureComponent 也会对所有的 props 做一个简单的检查,也没什么特别的,只是决定在哪里重新执行 render() 方法。
  • 啊,这么简单的解决方案。将您的 buildComplexHTMLFromData 移动到它自己的组件中,该组件只关心它的道具。然后你可以将shouldComponentUpdate 移动到该组件中,并让它只更新新的道具。
  • 听起来你的组件有太多关注点,可以分解成更小的子组件。
  • 感谢您的意见,但我想我已经考虑过这样做,但是您不认为仅仅容纳一个 &lt;input /&gt; 框就需要太多的组件中断。我有其他解决方案,只在输入标签中使用 defaultValue 可以解决这个目的,但我只是想知道 setState 如何可能允许这样的性能命中。
  • 这并不过分,它实际上更像是 React 的最佳实践。你不应该遇到你在使用 React 时遇到的问题。如果你这样做了,那么你可能做错了什么。将你的 UI 分解成最小的组件的想法是 React 的全部意义所在。祝你好运。
猜你喜欢
  • 2019-12-13
  • 2016-10-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多