I am trying to watch a field called party. after selecting those fields list of products will need to be rendered. I'm using react hook form where I used watch hook to subscribe to change.
<FormProvider {...methods}>
<form onSubmit={handleSubmit(onSubmit)}>
<Select
ref={ref}
options={partyOptions}
value={partyOptions.find(
(c) => c.value === value
)}
onChange={(val: any) => onChange(val.value)}
name={name}
/>
)}
<div className="card-body row">
<ProductContext.Provider value={[product, setProduct]}>
<ProductList partyId={partyId} />
</ProductContext.Provider>
</div>
</form>
On productlist component, i passed partyId as props and try to access API according to the partyId
export function ProductList({ partyId }: { partyId: any }) {
const { control } = useFormContext(); // retrieve all hook methods
const [productOptions, setProductOptions] = useState([] as any);
const productQuery = useQuery("products", () => searchProduct(partyId), {
enabled: partyId !== undefined,
});
if (productQuery.isFetched) {
setProductOptions(
productQuery.data.data.map((d: any) => ({
value: d.id,
label: d.name,
}))
);
}
I am getting Too many re-renders. React limits the number of renders to prevent an infinite loop. Is there any solution to not render multiple times?
You've to add more logic, setProductOptions is called at each react render. For example, you can use a useEffect to call setProductOptions only once.
export function ProductList({ partyId }: { partyId: any }) {
const { control } = useFormContext(); // retrieve all hook methods
const [productOptions, setProductOptions] = useState([] as any);
const productQuery = useQuery("products", () => searchProduct(partyId), {
enabled: partyId !== undefined,
});
useEffect(() => {
if (productQuery.isFetched) {
setProductOptions(
productQuery.data.data.map((d: any) => ({
value: d.id,
label: d.name,
})
)
);
}
}, [productQuery.isFetched, setProductOptions]);
Your problem is here:
if (productQuery.isFetched) {
setProductOptions(
productQuery.data.data.map((d: any) => ({
value: d.id,
label: d.name,
})
)
);
Every time the component is rendered, it triggers another state update with setProductOptions, which then causes another render and the cycle repeats infinitely. Consider using a useEffect hook instead:
useEffect(() => {
if (productQuery.isFetched) {
setProductOptions(
productQuery.data.data.map((d: any) => ({
value: d.id,
label: d.name,
})
)
}
}, [productQuery.isFetched);
Some more info on useEffect is available here: https://reactjs.org/docs/hooks-effect.html