[英]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>
<button type="button" onClick={() => setCount(count + 1)}>
+1
</button>
</div>
);
}
我们可以看到effect
在render
之后被有效地打印出来了。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.