使用 d3 更新 dom ref 并做出反应

Sat*_*tor 5 javascript dom d3.js reactjs react-hooks

我有functional component一个 d3函数,它将 a 附加pref安装上

我试图使用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

Run Code Online (Sandbox Code Playgroud)

Rod*_*ino 3

d3追加函数每次执行时都会创建一个新元素。

要始终拥有一个段落并且仅更新其值,您可以使用d3.join.

代替:

  d3.select(domRef.current)
      .append('p')
      .text(data)
Run Code Online (Sandbox Code Playgroud)

你可以使用:

  d3.select(domRef.current).selectAll('p')
    .data([data])
    .join('p')
    .text(d => d)
Run Code Online (Sandbox Code Playgroud)

逐行解释:

  • d3.select(domRef.current).selectAll('p')<p>:选择其中的所有元素domRef.current
  • .data([data]):将<p>元素绑定到数据数组。绑定时,数组中的每个项目都会有自己的<p>.
  • .join('p')join将创建一个选择,删除所有<p>没有关联数据的选择,并更新有数据的选择。这将为您留下 1 <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)
Run Code Online (Sandbox Code Playgroud)

上面的代码将产生 6 段:其中三段绑定到数组[1, 3, 5],另外三段绑定到[2, 4, 6]