Im using D3 with react useEffect
hook and i have click method wrapped with useCallback
hook and its updating the state, but when I’m clicking the element state is not updating at all. To stop re-rendering the D3 SVG element I don’t want to add counter
as dependency to useEffect
hook.
Is their way I can update the counter
state without adding counter
on useEffect
dependency?
import { useEffect, useState, useCallback } from "react";
import * as d3 from "d3";
export default function App() {
const [counter, setCounter] = useState(0);
const handleClick = useCallback(() => {
setCounter(counter + 1);
console.log(counter);
}, [counter]);
useEffect(() => {
const svg = d3.select("#svg");
//naming the selection
const redRect = svg
.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("width", 300)
.attr("height", 300)
.attr("fill", "red")
.attr("id", "red-rect");
redRect.on("click", handleClick);
}, []); // should not re-render the d3 with counter as the dependency
return <svg id="svg" />;
}
2
Answers
I have found the way to block useEffect redo all the D3 things with
useRef
, I use the useRef value asD3 SVG rect
then I'm checking ifrectRef.current
exists then ignore the D3 methods and bind thehandleClick
torectRef.current
its working.CodeSandbox
Pass a function to
setCounter
. The parameter of that function is the previous value of the state.useCallback
is not necessary here though, sincesetCounter
does not change identity.useReducer
is a better hook for just incrementing as well.Code Sandbox
Snippet