useAutoAppendCustomProps
A React hook for building multistep forms with ease.
Custom Properties
Hook snippet
Create a file called useAutoAppendCustomProps.tsx
with this snippet and import it in your component. and don't forget to adjust the hook according to your object interface.
const useAutoAppendCustomProps = (
{
productDetails,
setProductDetails
}: {
productDetails: Product;
setProductDetails: (productDetails: Product) => void
}) => {
const custom = useMemo(() => productDetails.properties.custom || [], [productDetails]);
useEffect(() => {
const emptyProps = custom.filter(
(prop) => !prop.propertyKey?.trim() && !prop.propertyValue?.trim()
);
const hasValidLast =
custom.length === 0 ||
(custom[custom.length - 1].propertyKey?.trim() &&
custom[custom.length - 1].propertyValue?.trim());
let newCustom = [...custom];
// Remove all empty props except one (keep one empty slot always)
if (emptyProps.length > 1) {
let emptyCount = 0;
newCustom = custom.filter((prop) => {
const isEmpty = !prop.propertyKey?.trim() && !prop.propertyValue?.trim();
if (isEmpty) {
emptyCount++;
return emptyCount === 1; // Keep only the first empty one
}
return true;
});
}
// Add new empty row if the last one is filled
if (hasValidLast) {
newCustom.push({ propertyKey: "", propertyValue: "" });
}
// Only update if something actually changed
if (JSON.stringify(newCustom) !== JSON.stringify(custom)) {
setProductDetails({
...productDetails,
properties: {
...productDetails.properties,
custom: newCustom,
},
});
}
}, [custom, productDetails, setProductDetails]);
};
Usage
Create an object for initialData
.
const initialData = {
properties: {
custom: [{ propertyKey: "", propertyValue: "" }],
};,
};
Import the hook and use it in your component. You can pass the state and state setter as an argument.
const [productDetails, setProductDetails] = useState(initialData);
useAutoAppendCustomProps({ productDetails, setProductDetails });
Helper functions for the hook. Use them for updating the state.
const handleKeyChange = (index: number, newKey: string) => {
const updated = [...productDetails.properties.custom];
updated[index].propertyKey = newKey;
setProductDetails({
...productDetails,
properties: { ...productDetails.properties, custom: updated },
});
};
const handleValueChange = (index: number, newValue: string) => {
const updated = [...productDetails.properties.custom];
updated[index].propertyValue = newValue;
setProductDetails({
...productDetails,
properties: { ...productDetails.properties, custom: updated },
});
};
const handleDelete = (index: number) => {
if (productDetails.properties.custom.length <= 1) return;
const updated = productDetails.properties.custom.filter((_, i) => i !== index);
setProductDetails({
...productDetails,
properties: { ...productDetails.properties, custom: updated },
});
};
Made by Dhvanit. Visit my portfolio.