Reputation: 81
I've written a hook for a Formik form I'm creating so that on a specific field, whenever a Selection option is selected, I want the hook to be called.
But what is happening, is that in every form field, on every key press, my hook is being called. Not sure what I'm doing wrong, but would love any pointers on what I can do to only call the hook on the select change.
Here's my displayProvinces.js
hook
import React from 'react';
import GetDistrictsAPI from '@/utils/services/GetDistrictsAPI';
import GetProvincesAPI from '@/utils/services/GetProvincesAPI';
import {Field, useFormikContext } from 'formik';
export default function DisplayProvinces(){
const [ provinces ] = GetProvincesAPI();
const handleSelectedProvince = useProvinces();
function useProvinces(){
console.log('Fired')
function handleSelectedProvince(pr) {
console.log('Selected Province = ' +pr)
let districts = GetDistrictsAPI(pr);
}
return handleSelectedProvince;
}
const {setFieldValue} = useFormikContext();
return (
<Field
as="select"
id="pxProvince"
name="pxProvince"
onChange={(e)=> {
handleSelectedProvince(e.target.value)
setFieldValue('pxProvince', e.target.value)
}}
className="mt-1 block w-full pl-3 pr-10 py-2 text-base border-gray-300 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm rounded-md"
>
{!provinces ? provinces : provinces.map((p, i) => (
<option key={i} value={p.prov_id}>{p.prov_name}</option>
))}
</Field>
)
}
In this code snippet, I can see 'Fired' in the console, for every key press, even though it is only supposed to be called from the associated select onChange
event.
Thanks in advance for any pointers!
And this is how I'm calling the component
<div className="col-span-6 sm:col-span-6 lg:col-span-2">
<CVLabel field="forms.rego.fields.px.province" required='1' />
<DisplayProvinces />
</div>
Upvotes: 1
Views: 1218
Reputation: 1094
On every onChange event, you're setting up the state(setFieldValue) which triggers react to re-evaluate and re-render the component, As the re-evaluation happens react again execute useProvinces() method which logs "Fired" in the console, and returns handleSelectedProvince reference.
There're two ways to solve your problem, either use useMemo() hooks which memo-ized the value returned by the passed function and recalculate the value when any dependency changes.
Or you can tweak in the code like this:
import React from 'react';
import GetDistrictsAPI from '@/utils/services/GetDistrictsAPI';
import GetProvincesAPI from '@/utils/services/GetProvincesAPI';
import {Field, useFormikContext } from 'formik';
export default function DisplayProvinces(){
const [ provinces ] = GetProvincesAPI();
function handleSelectedProvince(pr) {
console.log("Fired!!")
console.log('Selected Province = ' +pr)
let districts = GetDistrictsAPI(pr);
}
const {setFieldValue} = useFormikContext();
return (
<Field
as="select"
id="pxProvince"
name="pxProvince"
onChange={(e)=> {
handleSelectedProvince(e.target.value)
setFieldValue('pxProvince', e.target.value)
}}
className="mt-1 block w-full pl-3 pr-10 py-2 text-base border-gray-300 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm rounded-md"
>
{!provinces ? provinces : provinces.map((p, i) => (
<option key={i} value={p.prov_id}>{p.prov_name}</option>
))}
</Field>
)
}
Upvotes: 1
Reputation: 715
I think it happens because the re-rendering occurs. Every time your DisplayProvinces
component re-render, it will call the useProvinces()
function which will log Fired
. Try to use useMemo
hook to prevent your function getting re-initialized every component renders.
const handleSelectedProvince = useMemo(() => useProvinces(), []);
It will save the results of the useProvinces
(which is a handleSelectedProvince
function) even the component re-renders. More info about useMemo
here
Upvotes: 1