簡體   English   中英

如何阻止 D3 圖表在 React App 中的首次渲染時復制?

[英]How can I stop D3 chart from Duplicating on First Render in React App?

出於某種原因,我的 D3 圖表僅在第一次渲染時重復。 它將在第一個圖表的下方垂直堆疊第二個圖表。

但是當我點擊刷新時,它再也不會重復了。 有沒有辦法讓.forEach循環一次或放置某種中斷或條件來防止第一次重復渲染?

還是我需要修改useEffect()


export default function BarChart() {

    useEffect(() => {

        db.collection('revenue').get().then(res => { 
            let data = [];
            res.docs.forEach(doc => {   
                data.push(doc.data()); 
            });
      console.log(data);

            const svg = d3.select('.canvas')
                .append('svg')
                .attr('width', '640')
                .attr('height', '400');


            const margin = { top: 20, right: 20, bottom: 100, left: 100 };
            const graphWidth = 600 - margin.left - margin.right;
            const graphHeight = 400 - margin.top - margin.bottom;

            const graph = svg.append('g')
                .attr('width', graphWidth)
                .attr('height', graphHeight)
                .attr('transform', `translate(${margin.left}, ${margin.top})`);

            // create axes groups
            const xAxisGroup = graph.append('g')
                .attr('transform', `translate(0, ${graphHeight})`)

            const yAxisGroup = graph.append('g');

            const y = d3.scaleLinear()
                .domain([0, d3.max(data, d => d.amount)])
                .range([graphHeight, 0]);

            const x = d3.scaleBand()
                .domain(data.map(item => item.date))
                .range([0, graphWidth])
                .paddingInner(0.2)
                .paddingOuter(0.2);

            // join the data to circs
            const rects = graph.selectAll('rect')
                .data(data);

            // add attrs to circs already in the DOM
            rects.attr('width', '50')
                .attr("height", d => graphHeight - y(d.amount))
                .attr('fill', 'Red')
                .attr('x', d => x(d.date))
                .attr('y', d => y(d.amount));

            // append the enter selection to the DOM
            rects.enter()
                .append('rect')
                .attr('width', '50')
                .attr("height", 0)
                .attr('fill', 'Red')
                .attr('id', d => (d.id))
                .attr('x', (d) => x(d.date))
                .attr('y', graphHeight)
                .transition().duration(500)
                 .attr('y', d => y(d.amount))
                 .attr("height", d => graphHeight - y(d.amount))

            const xAxis = d3.axisBottom(x);
            const yAxis = d3.axisLeft(y)
                .ticks(4)
                .tickFormat(d => d + ' dollars');

            xAxisGroup.call(xAxis);
            yAxisGroup.call(yAxis);

            // Bottom Chart Text
            xAxisGroup.selectAll('text')
                .attr('fill', 'Teal')
                //.attr('font-weight', 'bold')
                .attr('transform', 'rotate(-40)')
                .attr('text-anchor', 'end')
        });

    }, []); // Array for data

    return (
        <div>
            <h1">Title</h1>
        </div>
    );

}

您可以嘗試將 SVG 添加到組件中,以便


    return (
        <div>
            <h1">Title</h1>
            <svg className="svg-canvas" width="640px" height="400px" />
        </div>
    );

和改變

const svg = d3.select('.canvas')
  .append('svg')
  .attr('width', '640')
  .attr('height', '400');

//to

const svg = d3.select('.svg-canvas')
svg.selectAll("*").remove()

這將確保在重新渲染之前 SVG 始終為空。 盡管如果您的數據更新,它將重新渲染所有內容。

我簡單地這樣做:

  // UseEffect
     React.useEffect(()=> {
          // Hide first svg
     let svg = document.getElementsByTagName('svg');
        // If data present create chart
        if(data){
        // Create chart
       D3Chart(chartDiv.current, data);

// Hide first empty svg
       svg[0].style.display='none';
         }
     },[data]);

你可以試試這個:

export function component_name {data, ...props} {
    const yourRef = useRef()
    useEffect(() => {
        /*All your code here*/
        yourRef.current.append(X) /*"X" is your first SVG element that contains the others*/
        return() => X.remove()

    }, [data])}

無論您在哪里調用組件:

<component_name data={data} />

每當您的數據發生更改時,您的組件都會被刪除。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM