繁体   English   中英

带有 useRef 和 useEffect 的自定义钩子

[英]Custom hook with useRef and useEffect

我正在阅读一篇使用自定义钩子和 d3 的博客文章。 它由以下代码组成:

条形图.js:

    import { useD3 } from './hooks/useD3';
    import React from 'react';
    import * as d3 from 'd3';

    function BarChart({ data }) {
      const ref = useD3(
        (svg) => {


          // console.log(svg)
          const height = 500;
          const width = 500;
          const margin = { top: 20, right: 30, bottom: 30, left: 40 };

          const x = d3
            .scaleBand()
            .domain(data.map((d) => d.year))
            .rangeRound([margin.left, width - margin.right])
            .padding(0.1);

          const y1 = d3
            .scaleLinear()
            .domain([0, d3.max(data, (d) => d.sales)])
            .rangeRound([height - margin.bottom, margin.top]);

          const xAxis = (g) =>
            g.attr("transform", `translate(0,${height - margin.bottom})`).call(
              d3
                .axisBottom(x)
                .tickValues(
                  d3
                    .ticks(...d3.extent(x.domain()), width / 40)
                    .filter((v) => x(v) !== undefined)
                )
                .tickSizeOuter(0)
            );

          const y1Axis = (g) =>
            g
              .attr("transform", `translate(${margin.left},0)`)
              .style("color", "steelblue")
              .call(d3.axisLeft(y1).ticks(null, "s"))
              .call((g) => g.select(".domain").remove())
              .call((g) =>
                g
                  .append("text")
                  .attr("x", -margin.left)
                  .attr("y", 10)
                  .attr("fill", "currentColor")
                  .attr("text-anchor", "start")
                  .text(data.y1)
              );

          svg.select(".x-axis").call(xAxis);
          svg.select(".y-axis").call(y1Axis);

          svg
            .select(".plot-area")
            .attr("fill", "steelblue")
            .selectAll(".bar")
            .data(data)
            .join("rect")
            .attr("class", "bar")
            .attr("x", (d) => x(d.year))
            .attr("width", x.bandwidth())
            .attr("y", (d) => y1(d.sales))
            .attr("height", (d) => y1(0) - y1(d.sales));
        },
        [data.length]
      );
      console.log("before svg render ",ref)
      return (
        <svg
          ref={ref}
          style={{
            height: 500,
            width: "100%",
            marginRight: "0px",
            marginLeft: "0px",
          }}
        >
          <g className="plot-area" />
          <g className="x-axis" />
          <g className="y-axis" />
        </svg>
      );
    }

    export default BarChart;

useD3.js 钩子:

    import React from 'react';
    import * as d3 from 'd3';

    export const useD3 = (renderChartFn, dependencies) => {
        const ref = React.useRef();

        React.useEffect(() => {
            renderChartFn(d3.select(ref.current));
            return () => {};
          }, dependencies);
        return ref;
    }

应用程序.js:

    import React from 'react';
    import BarChart from './BarChart';
    import './App.css';

    const data = [
      {year: 1980, efficiency: 24.3, sales: 8949000},
      {year: 1985, efficiency: 27.6, sales: 10979000},
      {year: 1990, efficiency: 28, sales: 9303000},
      {year: 1991, efficiency: 28.4, sales: 8185000},
      {year: 1992, efficiency: 27.9, sales: 8213000},
      {year: 1993, efficiency: 28.4, sales: 8518000},
      {year: 1994, efficiency: 28.3, sales: 8991000},
      {year: 1995, efficiency: 28.6, sales: 8620000},
      {year: 1996, efficiency: 28.5, sales: 8479000},
      {year: 1997, efficiency: 28.7, sales: 8217000},
      {year: 1998, efficiency: 28.8, sales: 8085000},
      {year: 1999, efficiency: 28.3, sales: 8638000},
      {year: 2000, efficiency: 28.5, sales: 8778000},
      {year: 2001, efficiency: 28.8, sales: 8352000},
      {year: 2002, efficiency: 29, sales: 8042000},
      {year: 2003, efficiency: 29.5, sales: 7556000},
      {year: 2004, efficiency: 29.5, sales: 7483000},
      {year: 2005, efficiency: 30.3, sales: 7660000},
      {year: 2006, efficiency: 30.1, sales: 7762000},
      {year: 2007, efficiency: 31.2, sales: 7562000},
      {year: 2008, efficiency: 31.5, sales: 6769000},
      {year: 2009, efficiency: 32.9, sales: 5402000},
      {year: 2010, efficiency: 33.9, sales: 5636000},
      {year: 2011, efficiency: 33.1, sales: 6093000},
      {year: 2012, efficiency: 35.3, sales: 7245000},
      {year: 2013, efficiency: 36.4, sales: 7586000},
      {year: 2014, efficiency: 36.5, sales: 7708000},
      {year: 2015, efficiency: 37.2, sales: 7517000},
      {year: 2016, efficiency: 37.7, sales: 6873000},
      {year: 2017, efficiency: 39.4, sales: 6081000},
    ]

    function App() {
      return (
        <div className="App">
          <header className="App-header">
            <BarChart data={data} />
          </header>
        </div>
      );
    }

    export default App;

当 BarChart 运行时,它会在其渲染方法之前调用 useD3 钩子。 在 useD3 钩子内部,代码运行并在返回 ref 之后; 行,useEffect 挂钩的回调应该运行。 这是我的思考过程,但显然反应不是那样工作的。 有人可以启发我吗? useEffect 回调究竟何时运行?

文档

传递给 useEffect 的函数将在渲染提交到屏幕后运行

因此传递给useEffect的函数将在组件渲染运行。

请注意,此函数可以选择返回一个清理函数 此函数将在下一个效果之前立即调用。

在执行下一个效果之前清理上一个效果

这是一个小例子

function App() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    console.log('effect ' + count);

    return () => console.log('cleanup effect ' + count);
  }, [count]);

  console.log('render ' + count);

  return (
    <div>
      <span>Count = {count}</span>
      &nbsp;
      <button type="button" onClick={() => setCount(count + 1)}>
        +1
      </button>
    </div>
  );
}

我们可以看到effectrender之后被有效地打印出来了。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM