[英]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.