What is the current behavior?
const [style, setStyle] = useState({ color: "#000000" });
const [signature, setSignature] = useState("Your Name");
useEffect(() => {
html2canvas(document.getElementById("signature-container")).then(
canvasEl => {
onChange(canvasEl.toDataURL());
},
);
}, [signature, style]);
<Text onChange={handleChange} />
It's warn need to add onChange
prop into dependency array of useEffect
but If I add onChange
prop into the array, useEffect
call recursively
What is the expected behavior?
Don't need to warn if user don't pass function props as dependency
Please read this, it answers this exact question. Let me know if you still have questions afterwards!
https://reactjs.org/docs/hooks-faq.html#is-it-safe-to-omit-functions-from-the-list-of-dependencies
@gaearon, thanks for the reference, I just updated the effect like this
useEffect(() => {
function emitChange() {
html2canvas(document.getElementById("signature-container")).then(
canvasEl => {
onChange(canvasEl.toDataURL());
},
);
}
emitChange();
}, [signature, style, onChange]);
but still It's calling recursively, and here is the resource usage
useEffect(() => {
function emitChange() {
html2canvas(document.getElementById("signature-container")).then(
canvasEl => {
onChange(canvasEl.toDataURL());
},
);
}
emitChange();
}, [signature, style]);
This is working as expected but linter says It's error
may I know, what I'm missing in this point ?
@gaearon may I know, How useEffect
depend on functional props ?
I think you missed the last part about useCallback in that link.
Specifically, I think you want something like this for your onChange. It鈥檚 hard to say more without seeing the whole code example as a sandbox.
@gaearon thanks for your explanations and sorry for your time
This is my working implementation https://codesandbox.io/s/v0lwkokq00
This is broken implementation https://codesandbox.io/s/vw62wz5o3 I just added onChange
props into the dependency list to break my implementation 馃槩
Implement notes:
Once the signature and style states change I need to parse signature preview into canvas to get signature input as image
I just add google font's stylesheet in this component because avoid load external resource until user need them, here I added in index.html
because codesandbox I load bootstrap from CDN.
calculate image from signature won't work inside input change because component won't render with current value so I pick useEffect
for this case
is this wrong implementation ? 馃槦
OK this is interesting. Normally you'd fix this by passing an onChange
with a stable identity:
const handleChange = useCallback(() => {
/* do stuff */
}, [/* its deps */])
<Text onChange={handleChange} />
But in your case it wouldn't work because it's inside Formik's render prop callback.
I'm not sure what's the idiomatic solution here from Formik's point of view.
But in your case, it seems like it's not actually important to re-run onChange
if the onChange
function itself changes. Therefore, you can use a ref to explicitly track its latest value:
const latestOnChange = useRef(onChange);
useEffect(() => {
latestOnChange.current = onChange;
}, [onChange]);
And then you can all latestOnChange.current
in the effect.
thanks @gaearon to spend your valuable time for this clarification, It's really help understood where I missed and how handle this kind of situation in future, thanks again!
Most helpful comment
OK this is interesting. Normally you'd fix this by passing an
onChange
with a stable identity:But in your case it wouldn't work because it's inside Formik's render prop callback.
I'm not sure what's the idiomatic solution here from Formik's point of view.
But in your case, it seems like it's not actually important to re-run
onChange
if theonChange
function itself changes. Therefore, you can use a ref to explicitly track its latest value:And then you can all
latestOnChange.current
in the effect.https://codesandbox.io/s/l5z8z3jj3z