[英]update dom ref using d3 and react
我有一个带有d3
函数的functional component
,它在安装时将p
附加到ref
我正在尝试使用useState
挂钩更改附加段落的文本内容
点击按钮<button type="button" onClick={(e)=> setData("bar")}>change data</button>
触发重新渲染,而不是更改p
标签的文本,一个新的d3 函数的版本被创建 --> 追加一个新的p
阅读参考更改时如何重新渲染建议使用useCallback
钩子,我不确定如何实现
如何在不创建新段落的情况下实现段落的重新渲染?
import {useEffect, useState, useRef} from 'react'
import * as d3 from 'd3'
function DomReference() {
const domRef = useRef()
const [data, setData] = useState("foo")
useEffect(()=>{
d3.select(domRef.current)
.append('p')
.text(data)
// re-render --> creates a new function
}, [data])
return (
<div ref={domRef}>
<button type="button" onClick={(e)=> setData("bar")}>change data</button>
</div>
)
}
export default DomReference
d3 append 函数在执行时总是会创建一个新元素。
要始终只有一个段落并且只更新其值,您可以使用d3.join
。
代替:
d3.select(domRef.current)
.append('p')
.text(data)
你可以使用:
d3.select(domRef.current).selectAll('p')
.data([data])
.join('p')
.text(d => d)
逐行解释:
d3.select(domRef.current).selectAll('p')
: 选择domRef.current
所有<p>
元素.data([data])
:将<p>
元素绑定到数据数组。 绑定时,数组中的每个项目都有自己的<p>
。.join('p')
: join
将创建一个选择,删除所有没有关联数据的<p>
,并更新有数据的那些。 这将为您留下一个<p>
,因为之前的.data()
调用在数组中只有一个元素.text(d => d)
:此回调是您访问与<p>
关联的数据的方式。 如果您不想删除所有其他<p>
,您可以使用一个类来缩小您的选择范围:
d3.select(domRef.current).selectAll('p.myOddParagraphs')
.data([1, 3, 5])
.join('p')
.classed('myOddParagraphs', true)
.text(d => d)
d3.select(domRef.current).selectAll('p.myEvenParagraphs')
.data([2, 4, 6])
.join('p')
.classed('myEvenParagraphs', true)
.text(d => d)
上面的代码将导致 6 段:三个绑定到[1, 3, 5]
数组,其他三个绑定到[2, 4, 6]
原则上,你不应该在使用 React 时尝试使用 D3 来改变 DOM,因为 React 不会意识到这样的变化。 这通常会导致很难发现和调试的非常讨厌的错误。 如果你发现自己在 React 中使用了attr
或append
,那你就错了;)
这并不是说你不能在 React 中使用 D3。 正确的方法是始终将 DOM 操作留给 React,并使用 D3 作为计算属性的引擎。 例如,当使用 d3 力布局时,您可以使用 D3 计算 (x,y) 坐标,并将它们作为道具传递,以便 React 处理协调等。
在上面的例子中,我建议将<p .../>
的渲染留给 React。 但是,我不知道您的最终目标是什么,因此除了将这个示例简单地转换为 React 之外,无法真正说出正确的方法是什么
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.