useState with array is always previous state inside my useCallback

Viewed 23

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.

0 Answers
Related