Closed shrihari1999 closed 1 year ago
:warning: | Newer Version of React Native is Available! |
---|---|
:information_source: | You are on a supported minor version, but it looks like there's a newer patch available. Please upgrade to the highest patch for your minor or latest and verify if the issue persists (alternatively, create a new project and repro the issue in it). If it does not repro, please let us know so we can close out this issue. This helps us ensure we are looking at issues that still exist in the most recent releases. |
Ok
warning Newer Version of React Native is Available! information_source You are on a supported minor version, but it looks like there's a newer patch available. Please upgrade to the highest patch for your minor or latest and verify if the issue persists (alternatively, create a new project and repro the issue in it). If it does not repro, please let us know so we can close out this issue. This helps us ensure we are looking at issues that still exist in the most recent releases.
I tried upgrading to the latest version (0.71.4). I can confirm that the issue still persists. Someone please help!
Hello, has anyone found a solution? I'm having the same problem.
We also experience this. I would be really nice to get fixed.
I found out it was introduces in this commit: https://github.com/facebook/react-native/commit/112bfeecfac393384de99866569b311dd00a6908 I tried to revert the changes locally and that fixed the issue. For now we will apply a patch in our repo the reverts the changes. I'm not really sure why the changes cause the issue. @s77rt could you maybe have a look as it seems like you did the changes.
In case anyone doesn't want to change the source code, I did a dirty settimeout workaround, that basically shields the component from updating for the first 300ms.
Someone please fix this officially!!
@remanation I have been looking into this. I think that the bug existed for long but instead of having onChangeText
fire it was onSelectionChange
. In the new version (0.71) every time onSelectonChange
is about to fire, we will first fire onChangeText
(to switch the order).
So the real bug to investigate is: Why onSelectionChange fires at render on a multiline TextInput. This is reproducible even on older versions (before the linked commit): https://snack.expo.dev/uy58XKz_S?platform=ios
0.70.6 not have this bug, I upgraded to 0.71.4 and now I have this bug
Just spent this evening chasing down this issue, we're on 0.71.4
, and then I stumbled across this issue. Bah. Appreciate you guys looking into this!
In case anyone doesn't want to change the source code, I did a dirty settimeout workaround, that basically shields the component from updating for the first 300ms.
Someone please fix this officially!!
As a temporary solution until the root-cause can be addressed I did the the same thing -- thanks for the recommendation @shrihari1999.
Quick update: Upgrading to 0.71.6 didn't fix it either
In case anyone doesn't want to change the source code, I did a dirty settimeout workaround, that basically shields the component from updating for the first 300ms. Someone please fix this officially!!
As a temporary solution until the root-cause can be addressed I did the the same thing -- thanks for the recommendation @shrihari1999.
Hi all, could one of you provide an example of this workaround?
EDIT:
I made myself it like this
type Props = {
text: string;
setText: React.Dispatch<React.SetStateAction<string>>;
maxLength: number;
};
export default (props: Props) => {
//github.com/facebook/react-native/issues/36494
React.useEffect(() => {
setTimeout(() => props.setText(props.text), 300);
}, []);
return (
<TextInput
value={props.text}
onChangeText={props.setText}
multiline
maxLength={props.maxLength}
/>
);
};
The problem with my approach is that the wrong value flashes on the input before the correct one is set.. =P
@rottabonus The point is to prevent onChangeText from affecting your state variables for 300ms. Try refactoring your code to this.
type Props = {
text: string;
setText: React.Dispatch<React.SetStateAction<string>>;
maxLength: number;
};
export default (props: Props) => {
const [onChangeShield, setOnChangeShield] = React.useState(true)
//github.com/facebook/react-native/issues/36494
React.useEffect(() => {
if(onChangeShield){
setTimeout(() => {
setOnChangeShield(false)
}, 300);
}
}, []);
const handleTextChange = (text) => {
if(onChangeShield){
return
}
props.setText(text)
}
return (
<TextInput
value={props.text}
onChangeText={handleTextChange}
multiline
maxLength={props.maxLength}
/>
);
};
@rottabonus The point is to prevent onChangeText from affecting your state variables for 300ms. Try refactoring your code to this.
type Props = { text: string; setText: React.Dispatch<React.SetStateAction<string>>; maxLength: number; }; export default (props: Props) => { const [onChangeShield, setOnChangeShield] = React.useState(true) //github.com/facebook/react-native/issues/36494 React.useEffect(() => { if(onChangeShield){ setTimeout(() => { setOnChangeShield(false) }, 300); } }, []); const handleTextChange = (text) => { if(onChangeShield){ return } props.setText(text) } return ( <TextInput value={props.text} onChangeText={handleTextChange} multiline maxLength={props.maxLength} /> ); };
Thanks for the suggestion!
It works better than my implementation, but still there is a tiny flash - but one you almost cannot see. That will have to do for now.. :p
Here is a small clip:
BTW the application is open sourced, so no worries of me showing something secret =)
I can confirm that onChangeText
(onSelectionChange
before https://github.com/facebook/react-native/commit/112bfeecfac393384de99866569b311dd00a6908) is called for every render of multiline TextInput.
@shrihari1999 do you confirm that maxLength
and text length is relevant here? For me this issue happens regardless of text length.
Sorry @dmytrorykun. I'm not aware of the onSelectionChange
/onChangeText
saga.
For me, there is no problem on an iOS device if:
a) maxLength
is not set
b) If initial state value length is less than half of maxLength
.
I'm not sure if its relevant to the underlying problem. But, I can confirm that this is my observation on any physical iOS device.
FYI there is a simple repro repo here, based on RN 0.72.1-rc1: https://github.com/renchap/react-native-36494-repro
It reproduces the initially reported issue, where the text is (partially) duplicated with multiline
+ maxLength
when the initial text is > maxLength /2
. This is due to onChangeText
(and onChange
) being called multiple times on render with the duplicated text.
I did not try without maxLength
I added a second repro case in my repo linked above, without maxLength
, and can confirm that onChangeText
(and onChange
) is called once when rendering the <TextInput multiline>
, regardless of the size of the initial value. This does not happen without multiline
.
So there are 2 parts of this bug:
<TextInput multiline>
component triggers a call to onChange
and onChangeText
on first render on iOSmaxLength
on the component, onChange
and onChangeText
are called with the initial value duplicated in the event's text to fill it to the defined maxLength
I see a fix for this was added - which I tried locally and worked. how soon will the fix be released?
@matthewmturner It's planned for 0.71.8, no date yet.
Has this already been released? I can still see the issue on Expo 48, React Native 0.71.8.
Has this already been released? I can still see the issue on Expo 48, React Native 0.71.8.
Never mind! I just saw that it is listed as one of the changes in React Native 0.72:
https://github.com/facebook/react-native/blob/main/CHANGELOG.md#ios-specific-9
just encountered this problem yesterday. Took me a while to figure out what was going on. A simple but dirty solution is to use the useRef hook. Set the initial hook to 0. in the onChangeText method, check to see if the useRef value is 0; if it is, do not execute the callback, otherwise execute the callback. From then on, keep incrementing the useRef value. This will persist across state changes
Experiencing this issue in react-native@0.72.3
. It is related to the multiline
prop itself rather than maxLength
. When text input has multiline
set to true
, onChangeText
callback invokes itself on the next batch/render. When you set multiline
to false, the bug disappears, meaning onChangeText
triggers only when we are actually setting the value.
Created basic snack example below, expo version 48
, rn version 0.71.x
:
https://snack.expo.dev/@tarikfp/textinput-onchangetext-bug-multiline
I confirm the issue. Indeed, when using multiline, OnChangeText starts to fire a large number of times. Disabling this setting resolves the issue. 0.72.3 react. this happens in a modal window on ios
Experiencing this issue in
react-native@0.72.3
. It is related to themultiline
prop itself rather thanmaxLength
. When text input hasmultiline
set totrue
,onChangeText
callback invokes itself on the next batch/render. When you setmultiline
to false, the bug disappears, meaningonChangeText
triggers only when we are actually setting the value.Created basic snack example below:
https://snack.expo.dev/@tarikfp/textinput-onchangetext-bug-multiline
Snack uses Expo 48 which should use RN 0.71.7 or something like that, not 0.72.
What I have experienced here in my tests is when multiline=true
applying masks to the value:
In all the cases, the onChangeText
works fine when you don't change value
programmatically, but if you do:
version | description |
---|---|
<= 0.71.7 | ⚠️ Changing value call onChangeText , then if you change value again the onChangeText will be called once more, creating an infinity loop. If you don't change value on every onChangeText , then will be fine. |
>= 0.71.8 && <= 0.71.12 | 🚨 changing value call onChangeText , then if you change value again the onChangeText will not be called, but if you type some new char the onChangeText will not be fired in the first time. |
>= 0.72.0 | ⚠️ Same as RN <= 0.71.7 |
Something curious that I would like to comment is that since I started working with RN in 2016 we have some kind of problem with multiline inputs, it seems to be a chronic problem with this component.
I confirm the issue. Indeed, when using multiline, OnChangeText starts to fire a large number of times. Disabling this setting resolves the issue. 0.72.3 react. this happens in a modal window on ios
same with version 0.72.4
Found a workaround, just in case anyone needs it You can use
<TextInput
multiline
numberOfLines={numberOfLines}
defaultValue={value}
onEndEditing={(e) => onChangeText(e.nativeEvent.text)}
/>
may not fit everyone, but at least does not go into infinite loop
Updating the behavior mentioned here: https://github.com/facebook/react-native/issues/36494#issuecomment-1678773893
version | description |
---|---|
<= 0.71.7 | ⚠️ Changing value call onChangeText , then if you change value again the onChangeText will be called once more, creating an infinity loop. If you don't change value on every onChangeText , then will be fine. |
>= 0.71.8 && <= 0.71.12 | 🚨 Changing value call onChangeText , then if you change value again the onChangeText will not be called, but if you type some new char the onChangeText will not be fired in the first time. |
= 0.71.13 (latest) | ⚠️ Same as RN <= 0.71.7 |
>= 0.72.0 | ⚠️ Same as RN <= 0.71.7 |
same issue on IOS with multiline set to true on rn 0.72.3 edit : as a workaround using defaultValue instead of value seems to fix it
<TextInput
defaultValue={value}
/>
If you use a pre-release version RN, it is for temporary use. You try this example code. Fix automatically occur text, also can paste text.
import { Platform, TextInput } from 'react-native';
const [value, setValue] = useState(props.value || '');
const maxLength = 100;
<TextInput
onChangeText={(newText) => {
if (Platform.OS === 'ios' &&
value &&
maxLength &&
value.length > (maxLength / 2) &&
newText.length - value.length >= maxLength - value.length) {
return;
}
setValue(newText);
}}
value={value}
maxLength={maxLength}
multiline
/>
Still an issue on 0.73.2
just encountered this problem yesterday. Took me a while to figure out what was going on. A simple but dirty solution is to use the useRef hook. Set the initial hook to 0. in the onChangeText method, check to see if the useRef value is 0; if it is, do not execute the callback, otherwise execute the callback. From then on, keep incrementing the useRef value. This will persist across state changes
Could you please provide a reference of your alternative solution? In my case, not only is onChangeText
being called repeatedly, but its value is also changed. For example, in my case, I have maxLength={8}
and if I type "Abcde"
and then programmtically set the state to empty string and navigate to another screen; and then coming back to the screen and programmatically setting the state to "Abcde"
again, the text input then incorrectly renders the string "AbcAbcde". I have encountered very similar behavior to this issue: https://github.com/facebook/react-native/issues/44566
Thanks for your help in advance!
Description
Consider a TextInput that has maxLength set and multiline true. When the text input's initial value's length is more than half the maxLength value, onChangeText is automatically called on render.
I am unable to reproduce this in a snack, happens on multiple iOS devices I've tried. No issue with android.
React Native Version
0.71.3
Output of
npx react-native info
System: OS: Linux 4.15 Ubuntu 16.04.7 LTS (Xenial Xerus) CPU: (4) x64 Intel(R) Core(TM) i5-2320 CPU @ 3.00GHz Memory: 3.66 GB / 7.76 GB Shell: 4.3.48 - /bin/bash Binaries: Node: 16.17.0 - ~/.config/nvm/versions/node/v16.17.0/bin/node Yarn: 1.22.19 - ~/.config/nvm/versions/node/v16.17.0/bin/yarn npm: 8.15.0 - ~/.config/nvm/versions/node/v16.17.0/bin/npm Watchman: 4.9.0 - /usr/local/bin/watchman SDKs: Android SDK: API Levels: 28, 29, 30, 31 Build Tools: 28.0.3, 29.0.2, 29.0.3 System Images: android-27 | Google Play Intel x86 Atom Android NDK: Not Found IDEs: Android Studio: Not Found Languages: Java: 1.8.0_251 - /home/shrihari/jdk1.8.0_251/bin/javac npmPackages: @react-native-community/cli: Not Found react: 18.2.0 => 18.2.0 react-native: 0.71.3 => 0.71.3 npmGlobalPackages: react-native: Not Found
Steps to reproduce
Snack, code example, screenshot, or link to a repository
I am using Expo SDK 48. I am also running the lastest version of Expo GO