在React中操作DOM

3

我知道直接在React中操作DOM不是一个好的做法,因为React协调引擎在比较虚拟DOM和真实DOM时会影响性能。

但是如果我像这样做呢?

这里只是展示情景以解释问题,不需要针对特定情景回答,而是谈论这种做法的缺点

情景:1

state = {
   innerHTML : ""
}

document.getElementById("test").innerHTML = this.state.innerHTML

handleChange(){
  //...handles change in state
}

场景:2

state = {
    color:"red"
}

document.getElementById("test").style.color = this.state.color

handleChange(color){
    this.setState({color})
}

在这种情况下,React知道它需要重新渲染,因为我正在改变状态,从而保持虚拟DOM和真实DOM的一致性。
那么在所有这些情况下,如果我可以使用状态来维护一致性并对真实DOM进行更改,是否仍然不建议以这种方式更改真实DOM?

是的,在React中直接操作DOM是非常反模式的。 - Drew Reese
2个回答

2

我想知道这是否是个好主意。我已经了解到其他替代方案了。谢谢帮助 :) - kooskoos

2

如果是这种情况,你不应该直接设置innerHTML,而应该使用dangerouslySetInnerHTML

class Component extends React.Component {
  state = {
    innerHTML: '',
  }

  handleChange() {
    this.setState({ innerHTML: '...' });
  }

  render() {
    return <div dangerouslySetInnerHTML={ { __html: this.state.innerHTML } }></div>;
  }
}

如文档所述:

dangerouslySetInnerHTML

dangerouslySetInnerHTML 是 React 在浏览器 DOM 中使用 innerHTML 的替代品。一般来说,从代码中设置 HTML 是有风险的,因为很容易无意中使用户暴露于跨站脚本(XSS)攻击之下。因此,您可以直接从 React 设置 HTML,但必须打出 dangerouslySetInnerHTML 并传递一个带有 __html 键的对象,以提醒自己它是危险的。

而且,在使用 dangerouslySetInnerHTML 时,React 在比较虚拟 DOM 和真实 DOM (reconciliation) 时会忽略该部分的 DOM,因此它的性能更高,因为它需要做的工作更少。

在任何情况下,如果您这样做:

document.getElementById('test').innerHTML = this.state.innerHTML;

在代码的某个时刻,可能是在componentDidUpdate()中,然后render()会再次调用(当您更新状态或父组件重新渲染时),您的更改将被覆盖,因此您需要不断地更新它,这可能会产生一个小但明显的闪烁,并降低性能,因为每次渲染都必须更新DOM 2次(一次来自React,另一次来自innerHTML)。


最好使用其中一个避免使用dSIH的库。 - Dave Newton
1
我意识到了。但是我使用这个例子是为了询问这种情况是否是一个有效的解决方案。我并不特别面临这个问题。但还是谢谢你的努力 :) - kooskoos
@kooskoos请检查更新后的答案,我已经添加了更多关于你所询问的方法的缺点的细节。 - Danziger
据我所见,setState 是异步的。因此,当我调用 setState 时,更改不会立即生效,而是在真正的 DOM 更改后,当 React 重新渲染虚拟 DOM 时也会更改。从而保持一致性,避免闪烁。 - kooskoos
您能否检查一下我添加的场景,以便直接在DOM中更改样式? - kooskoos

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接