【问题标题】:update dom ref using d3 and react使用 d3 更新 dom ref 并做出反应
【发布时间】:2021-06-23 12:26:40
【问题描述】:

我有一个functional component 和一个d3 函数,它在挂载时将p 附加到ref

我正在尝试使用 useState 挂钩更改附加段落的文本内容

点击按钮 <button type="button" onClick={(e)=> setData("bar")}>change data</button> 触发重新渲染,而不是更改 p 标签的文本,而是创建一个新版本的 d3 函数 --> 附加一个新的 p

阅读How to rerender when refs change建议使用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

【问题讨论】:

    标签: javascript reactjs dom d3.js react-hooks


    【解决方案1】:

    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中的所有&lt;p&gt;元素
    • .data([data]):将@​​987654330@ 元素绑定到数据数组。绑定时,数组中的每一项都会有自己的&lt;p&gt;
    • .join('p')join 将创建一个选择,删除所有没有关联数据的&lt;p&gt;,并更新有数据的选择。这将为您留下一个 &lt;p&gt;,因为之前的 .data() 调用在数组中只有一个元素
    • .text(d =&gt; d):此回调是您访问与&lt;p&gt; 关联的数据的方式。

    作为补充:

    如果您不想删除所有其他 &lt;p&gt;,可以使用类来缩小选择范围:

      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 中真正使用 appendattrtext,这是一种糟糕的做法。原因是 React 不知道这些变化,并且它们超出了协调过程,通常会导致难以捕捉的令人讨厌的错误。 JSX 拥有 DOM 操作所需的一切,d3 应该只用于行为逻辑(例如计算位置等)
    【解决方案2】:

    原则上,您不应该在使用 React 时尝试使用 D3 来改变 DOM,因为 React 不会意识到这些变化。这通常会导致很难发现和调试的非常讨厌的错误。如果你发现自己在 React 中使用 attrappend,那你就用错了 ;)

    这并不是说你不能在 React 中使用 D3。正确的方法是始终将 DOM 操作留给 React,并使用 D3 作为计算属性的引擎。例如。使用 d3 强制布局时,您可以使用 D3 计算 (x,y) 坐标,并将它们作为道具传递,以便 React 处理协调等。

    在上面的示例中,我建议将 &lt;p .../&gt; 的渲染留给 React。但是我不知道您的最终目标是什么,所以除了将这个示例简单地转换为 React 之外,我无法真正说出正确的方法

    【讨论】:

      猜你喜欢
      • 2021-08-19
      • 2021-02-05
      • 2019-10-20
      • 1970-01-01
      • 2020-07-24
      • 2021-02-20
      • 1970-01-01
      • 2021-03-29
      • 2017-08-04
      相关资源
      最近更新 更多