I am making a kind of input in react.
I have the following
=> A component returning a onSelectionChange that return an array of selected element (works fine)
useEffect(() => {
onSelectionChange?.(selection.items);
}, [selection]);
=> A input that wrap the above component and contain a button save/cancel. When use click save, I want to dispatch a onChange with the latest value selected. If user click cancel, it will reset to initial value. ( I intentionally removed some of the component code to keep the problematic parts)
export const VariantsInput = forwardRef<any, any>(
({ value = [], ...rest }, ref) => {
//....
const [selectedProducts, setSelectedProducts] = useState<VariantSetDetail[]>(value);
const onValidate = useCallback(() => {
console.log(selectedProducts); // always the previous state of selectedProducts
onChange(selectedProducts);
closeDialog(dialogId);
}, [selectedProducts]);
useEffect(() => {
console.log(selectedProducts); // always the latest state of selectedProducts
}, [selectedProducts]);
//...
<VariantSelector
selectedSku={value}
onSelectionChange={(selection) => {
setSelectedProducts(() => [
...selection.map((selected) => {
const alreadySelected = value.find(
(product) =>
product.productVariantId === selected.productVariantId
);
return alreadySelected ? alreadySelected : selected;
}),
]);
}}
/>
<button onClick={onValidate}> Save</button>
//....
The issue is selectedProducts is always the previous state in the onValidate. If I check all my events onSelectionChange, or put log inside the effect and the root of the component to display the state, it contains exactly what I want. But in the on validate, it is always []....
I am really confused as to why.