Let's say I have 3 inputs: rate, sendAmount, and receiveAmount. I put that 3 inputs on useEffect diffing params. The rules are:
receiveAmount = sendAmount * ratesendAmount = receiveAmount / ratereceiveAmount = sendAmount * rate when sendAmount > 0 or I calculate sendAmount = receiveAmount / rate when receiveAmount > 0Here is the codesandbox https://codesandbox.io/s/pkl6vn7x6j to demonstrate the problem.
Is there a way to compare the oldValues and newValues like on componentDidUpdate instead of making 3 handlers for this case?
Thanks
Here is my final solution with usePrevious
https://codesandbox.io/s/30n01w2r06
In this case, I cannot use multiple useEffect because each change is leading to the same network call. That's why I also use changeCount to track the change too. This changeCount also helpful to track changes from local only, so I can prevent unnecessary network call because of changes from the server.
You can write a custom hook to provide you a previous props using useRef
function usePrevious(value) {
const ref = useRef();
useEffect(() => {
ref.current = value;
});
return ref.current;
}
and then use it in useEffect
const Component = (props) => {
const {receiveAmount, sendAmount } = props
const prevAmount = usePrevious({receiveAmount, sendAmount});
useEffect(() => {
if(prevAmount.receiveAmount !== receiveAmount) {
// process here
}
if(prevAmount.sendAmount !== sendAmount) {
// process here
}
}, [receiveAmount, sendAmount])
}
However its clearer and probably better and clearer to read and understand if you use two useEffect separately for each change id you want to process them separately
Incase anybody is looking for a TypeScript version of usePrevious:
In a .tsx module:
import { useEffect, useRef } from "react";
const usePrevious = <T extends unknown>(value: T): T | undefined => {
const ref = useRef<T>();
useEffect(() => {
ref.current = value;
});
return ref.current;
};
Or in a .ts module:
import { useEffect, useRef } from "react";
const usePrevious = <T>(value: T): T | undefined => {
const ref = useRef<T>();
useEffect(() => {
ref.current = value;
});
return ref.current;
};
const Component = (props) => {
useEffect(() => {
console.log("val1 has changed");
}, [val1]);
return <div>...</div>;
};
Comparing a current value to a previous value is a common pattern, and justifies a custom hook of it's own that hides implementation details.
const Component = (props) => {
const hasVal1Changed = useHasChanged(val1)
useEffect(() => {
if (hasVal1Changed ) {
console.log("val1 has changed");
}
});
return <div>...</div>;
};
const useHasChanged= (val: any) => {
const prevVal = usePrevious(val)
return prevVal !== val
}
const usePrevious = (value) => {
const ref = useRef();
useEffect(() => {
ref.current = value;
});
return ref.current;
}