You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
bug: changing value of component in ionChange results in an infinite loop #20106
Current behavior:
When the value of an Ionic input element is changed from OUTSIDE of the element, the element's onIonChange is triggered, thereby duplicating the change event.
Expected behavior:
As with every other React input, the onIonChange should only be triggered when the value was change from the element itself.
Steps to reproduce:
See console in included stackblitz.
Both the IonInput and regular input are controlled via the same value.
When changing it from the IonInput, only the onIonChange is triggered.
When changing it from the regular input, the input's onChange is called AS WELL AS the onIonChange from the IonInput.
Other information:
This same bug is happening with other Ionic inputs as well. I haven't tested all of them, but it is happening with at least IonToggle and IonDateTime.
This is bad because unless each input has its own separate controlled state, doing something like clearing a state object could trigger 10+ onIonChange events, leading to race conditions and other annoyances.
changed the title [-]bug: Controlled Inputs trigger onIonChange even if the change was from other components[/-][+]bug: IonInput fires onIonChange when value is change outside of IonInput[/+]on Dec 18, 2019
ionChange is triggered with every change of the input value, either through user input or programmatically. If you want your handler to be triggered only when the user changes the input, you should use ionInput event instead.
Reacted by Reyna D., Quang, Johan, Wael Bettayeb, Jin Yu Zhang, YouYue, Krestian Weken and Zack Madden
@masimplo Thanks for that clarification; I now see what happened. The event types for onIonInput may be broken. I tried using onIonInput and was getting Property 'value' does not exist on type 'EventTarget', but if I declare event: any it does work.
And as a followup, it seems that other inputs don't have onIonInput or anything like it that only triggers for inputs via that element. For example, IonDateTime and IonToggle only have onIonChange. What are we supposed to do in those cases?
Reacted by Max Meijer, David ML, antoninbeaufort, svrakata, Gunnar Beutner, Reyna D., d00M_L0rDz, Adam Kusber and Filipe Magalhaes Gomes
Hi, I have the same problem, this is my organization :
App (contains filters state and update methods)
Menu (contains filters form)
FirstPage (display Menu and results)
SecondPage (display another filters form and results)
I have 2 forms that use a single state and when I change a value of a field from one form, it trigger the update method on both forms. (this is a problem because I fetch data on each update)
How can I trigger only one time the update method ? onIonInput is not available on IonSegment too...
My first example is not really explicit because I can use differents filters on differents pages but I have another example where I haven't found a solution :
Form (keep all states of input in one object and contains update method)
Step 1
Step 2
At the end of the form I want to reset it, but if I do it it just reset some fields because they all interacts with the same object and re-trigger the update method for each input... The only workaround I have is to use one state for each input and when reset the form, call the setter of each state 😞
EDIT:
For those who would have the same problem as me: to avoid state modification conflicts when reacting it is possible with useState to modify from the previous state.
Example:
setSomething({
...something,
anyProperty: value
})
becomes:
setSomething(previousState => ({
...previousState,
anyProperty: value
}))
ionChange is triggered with every change of the input value, either through user input or programmatically. If you want your handler to be triggered only when the user changes the input, you should use ionInput event instead.
Any ideas how to deal with that? I have IonSelect that is wired with redux state and when logic other than user interacting with that component is updating the values the ionOnChange event is triggered. How to know where the change is coming from?
onIonInput is working for me (4.11.10), but somehow when i change the value (type=date or type=time) outside of the onIonInput handler, it doesn't rerender with the new value.
This is quite an annoying "feature". Additionally, onIonChange calls the function from the previous render, which makes the issue even more annoying.
My current workaround is to keep a useRef reference that is updated on every render. Then when onIonChange is called, you can ignore the call if the new value is the same as the value in useRef.
Note that this feature ruins use-cases where one input field depends on another input field. You can end up in a weird update loop and the end state becomes completely unpredictable.
UPDATE 12/20: The "key" workaround is not fully working after all. If you make a selection and hit OK all is well. If however you open the select and hit OK without making a change (so it's the same selection) the infinite loop still happens.
Just want to mention that I also ran into this infinite loop using an IonSelect (Ionic React v5) alongside React Hook Form as a Controlled component.
I experience it when select options are simple strings and multiple is true. I also notice it as well as for complex object options in both single and multiple selects.
I do not experience it for simple string single select.
For anyone else using RHF alongside Ionic, I went with a variation on @Najros "bug-around". Thanks for that!
I did manage to get it working with the more complex object value select. It's a bit more complicated as it involves the compareWith prop and JSON.stringify but am happy to share if anyone is facing a similar hurdle.
I'll update with any changes after upgrading to Ionic v6
Facing the same loop issue in combination with React Hook Form (Controller) using Ionic v6.
The mentioned key workaround only works as long as you don't hit "OK" again without changing the selected value.
Edit: Workaround with mentioned hasFous & key prop in React Hook Form
well,i tried the workaround above such as hasFous & key , but this doesn't work. When i add random key on IonToggle,it works and won't trigger more or infinite loop of onIonChange.
<IonToggle
slot='end'
key={Math.random()}
checked={item.enabled}
disabled={item.status === 'EXPIRED'}
onIonChange={(e) => onChangeDelegationStatus(e, item)}
/>
Hi. I'm still running into these infinite loops with React Hook Form and so far none of the above workarounds do the trick. What I have so far found to work is to only call onChange if the value has changed. This new workaround seems to work because opening the Select and not changing anything then hitting OK is what throws me into a loop (with or without using any of the above suggestions).
<Controllername="multiSelectExample"control={control}render={({field: { value, onChange }})=>{return(<IonSelectkey={value.toString()}multiplevalue={value}onIonChange={(e: CustomEvent<SelectChangeEventDetail<Array<string>>>)=>{// EARLY RETURN IF VALUE WASN'T CHANGEDif(JSON.stringify(e.detail.value)===JSON.stringify(value)){
return
}onChange(e.detail.value)}}>{selectOptions.map((option)=>(<IonSelectOptionkey={option.value}value={option.value}>{option.label}</IonSelectOption>))}</IonSelect>)}}/>
Hi. I'm still running into these infinite loops with React Hook Form and so far none of the above workarounds do the trick. What I have so far found to work is to only call onChange if the value has changed. This new workaround seems to work because opening the Select and not changing anything then hitting OK is what throws me into a loop (with or without using any of the above suggestions).
<Controllername="multiSelectExample"control={control}render={({field: { value, onChange }})=>{return(<IonSelectkey={value.toString()}multiplevalue={value}onIonChange={(e: CustomEvent<SelectChangeEventDetail<Array<string>>>)=>{// EARLY RETURN IF VALUE WASN'T CHANGEDif(JSON.stringify(e.detail.value)===JSON.stringify(value)){
return
}onChange(e.detail.value)}}>{selectOptions.map((option)=>(<IonSelectOptionkey={option.value}value={option.value}>{option.label}</IonSelectOption>))}</IonSelect>)}}/>
Thanks for the issue! This issue is being locked to prevent comments that are not relevant to the original issue. If this is still an issue with the latest version of Ionic, please create a new issue and ensure the template is fully filled out.
Activity
[-]bug: Controlled Inputs trigger onIonChange even if the change was from other components[/-][+]bug: IonInput fires onIonChange when value is change outside of IonInput[/+]masimplo commentedon Dec 19, 2019
ionChange is triggered with every change of the input value, either through user input or programmatically. If you want your handler to be triggered only when the user changes the input, you should use ionInput event instead.
ebk46 commentedon Dec 20, 2019
@masimplo Thanks for that clarification; I now see what happened. The event types for onIonInput may be broken. I tried using
onIonInputand was gettingProperty 'value' does not exist on type 'EventTarget', but if I declareevent: anyit does work.ebk46 commentedon Dec 20, 2019
And as a followup, it seems that other inputs don't have onIonInput or anything like it that only triggers for inputs via that element. For example, IonDateTime and IonToggle only have onIonChange. What are we supposed to do in those cases?
antoninbeaufort commentedon Feb 6, 2020
Hi, I have the same problem, this is my organization :
I have 2 forms that use a single state and when I change a value of a field from one form, it trigger the update method on both forms. (this is a problem because I fetch data on each update)
How can I trigger only one time the update method ?
onIonInputis not available on IonSegment too...antoninbeaufort commentedon Feb 7, 2020
My first example is not really explicit because I can use differents filters on differents pages but I have another example where I haven't found a solution :
At the end of the form I want to reset it, but if I do it it just reset some fields because they all interacts with the same object and re-trigger the update method for each input... The only workaround I have is to use one state for each input and when reset the form, call the setter of each state 😞
EDIT:
For those who would have the same problem as me: to avoid state modification conflicts when reacting it is possible with useState to modify from the previous state.
Example:
becomes:
KingMatrix1989 commentedon Mar 8, 2020
@ebk46, Hi Evan. It seems there is not any good document or sample code for Ionic-React. Can you guide me, please?
KingMatrix1989 commentedon Mar 8, 2020
Same problem exist about onIonInput event
svrakata commentedon May 31, 2020
Any ideas how to deal with that? I have IonSelect that is wired with redux state and when logic other than user interacting with that component is updating the values the ionOnChange event is triggered. How to know where the change is coming from?
jayenashar commentedon Jun 20, 2020
onIonInputis working for me (4.11.10), but somehow when i change the value (type=dateortype=time) outside of theonIonInputhandler, it doesn't rerender with the new value.oskarkook commentedon Aug 20, 2020
This is quite an annoying "feature". Additionally,
onIonChangecalls the function from the previous render, which makes the issue even more annoying.My current workaround is to keep a
useRefreference that is updated on every render. Then whenonIonChangeis called, you can ignore the call if the new value is the same as the value inuseRef.oskarkook commentedon Aug 20, 2020
Note that this feature ruins use-cases where one input field depends on another input field. You can end up in a weird update loop and the end state becomes completely unpredictable.
11 remaining items
ihorbond commentedon Jun 18, 2021
Is there any update on this?
dev-sammy commentedon Sep 8, 2021
I am an Angular guy, I don't know if it will help in react components but you can check this I have found a workaround.
ion-toggle unnecessarily triggers change event when default value is true
babycourageous commentedon Dec 19, 2021
UPDATE 12/20: The "key" workaround is not fully working after all. If you make a selection and hit OK all is well. If however you open the select and hit OK without making a change (so it's the same selection) the infinite loop still happens.
Just want to mention that I also ran into this infinite loop using an
IonSelect(Ionic React v5) alongside React Hook Form as a Controlled component.I experience it when select options are simple strings and
multipleis true. I also notice it as well as for complex object options in both single and multiple selects.I do not experience it for simple string single select.
For anyone else using RHF alongside Ionic, I went with a variation on @Najros "bug-around". Thanks for that!
I did manage to get it working with the more complex object value select. It's a bit more complicated as it involves the
compareWithprop andJSON.stringifybut am happy to share if anyone is facing a similar hurdle.I'll update with any changes after upgrading to Ionic v6
otemler commentedon Jan 7, 2022
Facing the same loop issue in combination with React Hook Form (Controller) using Ionic v6.
The mentioned
keyworkaround only works as long as you don't hit "OK" again without changing the selected value.Edit: Workaround with mentioned
hasFous&keyprop in React Hook FormThat's working for me even when I update with no value changed.
XueMeijing commentedon May 18, 2022
well,i tried the workaround above such as hasFous & key , but this doesn't work. When i add random key on IonToggle,it works and won't trigger more or infinite loop of onIonChange.
<IonToggle
slot='end'
key={Math.random()}
checked={item.enabled}
disabled={item.status === 'EXPIRED'}
onIonChange={(e) => onChangeDelegationStatus(e, item)}
/>
babycourageous commentedon Jun 7, 2022
Hi. I'm still running into these infinite loops with React Hook Form and so far none of the above workarounds do the trick. What I have so far found to work is to only call
onChangeif the value has changed. This new workaround seems to work because opening the Select and not changing anything then hitting OK is what throws me into a loop (with or without using any of the above suggestions).While the above is a React Hook Form sample, the issue doesn't seem to be limited to the React Hook Form integration. #24691 points back to the original RHF issue which has a non-RHF repro - https://codesandbox.io/s/thirsty-pasteur-wqpuz?file=/src/App.tsx:137-143
Hope all this extra info and another workaround is helpful!
sean-perkins commentedon Jun 24, 2022
Hello everyone, I've created an RFC to discuss changes to the API design that should correct this issue: #25532
Please share your thoughts and if there is anything we may be missing.
Thanks!
captainR0bbo commentedon Jun 30, 2022
I also commented on #24584 - try an earlier version of react-hook-form version if you need a workaround for now. 7.12.2 worked for me.
feat(input): ionChange will only emit from user committed changes (#2…
sean-perkins commentedon Sep 12, 2022
This issue has been resolved in this pull request: #25858 and will be available in the next major release (v7) of Ionic.
ionitron-bot commentedon Oct 12, 2022
Thanks for the issue! This issue is being locked to prevent comments that are not relevant to the original issue. If this is still an issue with the latest version of Ionic, please create a new issue and ensure the template is fully filled out.