Since I want my variation form to be dynamic, I have used the concept of field array from react-hook-form. For the select field I am using react-select which is used for taking multiple values for a particular option from the user. This is how I have done
import React from "react";
import { useForm, useFieldArray } from "react-hook-form";
import ReactSelect from "./Select";
import Input from "./Input";
import VariationPreview from "./VariationPreview";
const initialValues = {
variations: [
{
id: 1,
option: "Size",
values: [
{ id: 1, label: "SM", value: "sm" },
{ id: 2, label: "MD", value: "md" }
]
},
{
id: 2,
option: "Color",
values: [
{ id: 1, label: "Red", value: "red" },
{ id: 2, label: "Blue", value: "blue" }
]
}
]
};
const VariationSetup = () => {
const {
register,
control,
handleSubmit,
formState: { errors },
watch,
getValues
} = useForm({
defaultValues: initialValues ?? {}
});
const { fields, append, remove } = useFieldArray({
control, // control props comes from useForm (optional: if you are using FormContext)
name: "variations" // unique name for your Field Array
});
const variants = watch("variations");
console.log("variants", variants);
return (
<>
<p className="font-semibold mb-4 text-md">Options</p>
{fields.map((field, index) => {
return (
<React.Fragment key={field.id}>
<div className="flex mb-4" key={field.id}>
<div className="w-full md:w-4/12">
<Input
name={`variations.${index}.option`}
label="Option"
placeholder="Choose option"
options={VARIATION_OPTION}
helperText="Choose option that can be applied as variants for a product"
errors={errors}
register={register}
/>
</div>
<div className="w-full md:ml-4 md:w-8/12">
<ReactSelect
name={`variations.${index}.values`}
label=""
placeholder="Choose value"
options={[]}
helperText="You can choose multiple values"
wrapperClassName="mt-7"
errors={errors}
register={register}
isCreateable
/>
</div>
</div>
</React.Fragment>
);
})}
<button
className="bg-gray-200 p-3"
type="button"
onClick={() => append({ option: "", value: "" })}
>
Add option
</button>
<div className="divide-y"></div>
{/* PREVIEW */}
<VariationPreview variations={watch("variations")} />
</>
);
};
export default VariationSetup;
const VARIATION_OPTION = [
{ id: 1, label: "Size", value: "size" },
{ id: 2, label: "Color", value: "color" }
];
this is the react-select with hook-form binding
import { Controller, useForm } from "react-hook-form";
import Select from "react-select";
import CreatableSelect from "react-select/creatable";
export default function ReactSelect({
disabled,
label,
helperText,
name,
placeholder,
options,
defaultValue,
className,
labelClassName,
wrapperClassName,
isCreateable = false
}) {
const {
control,
formState: { errors }
} = useForm();
const getDefaultValue = (value) => {
if (value && value.length) {
return value[0];
} else return value;
};
return (
<div className={wrapperClassName ? wrapperClassName : ""}>
{/* TODO: Label as a separate component */}
<label
htmlFor={name}
className={
labelClassName
? labelClassName
: "block font-semibold mb-2 text-gray-700 text-sm tracking-wide uppercase"
}
>
{label}
</label>
<div className="mt-1 relative">
<Controller
name={name}
defaultValue={getDefaultValue(defaultValue)}
control={control}
render={({ field }) => {
const styles = errors[name] ? errorStyles : customStyles;
if (isCreateable) {
return (
<CreatableSelect
isMulti
{...field}
isDisabled={disabled}
placeholder={placeholder}
options={options}
styles={styles}
className={className}
/>
);
} else {
return (
<Select
{...field}
isDisabled={disabled}
placeholder={placeholder}
options={options}
styles={styles}
className={className}
/>
);
}
}}
/>
</div>
</div>
);
}
Here the problem is when I update values field the variations object does not get updated because of which I cannot update Variation Preview table. Also when if I add new option, the option key gets updated and is reflected in VariationPreview table but when I add values for that option the values object is shown empty. Could anyone point me where i did the mistake? I have a code in playground either
https://codesandbox.io/s/elegant-robinson-fiujlj?file=/src/Variation.jsx:0-2764