Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

iOS TextInput - text undo/redo doesn't work if value, defaultValue, or onChange is set #29572

Open
cristianoccazinsp opened this issue Aug 6, 2020 · 16 comments
Labels
Component: TextInput Related to the TextInput component. Platform: iOS iOS applications.

Comments

@cristianoccazinsp
Copy link
Contributor

cristianoccazinsp commented Aug 6, 2020

Please provide all the information requested. Issues that do not follow this format are likely to stall.

Description

Setting value, or defaultValue with onChange will cause iOS undo/redo keyboard feature (mostly on iPads) to break or rarely work. Additionally, it may cause a native crash from time to time.

Basically, the undo button gets enabled for half a second, and then gets disabled again. The issue will not happen if value or defaultValue is not set. I suspect this is related to the code that sends the JS value to native which in turn clears/updates the native input.

React Native version:

Run react-native info in your terminal and copy the results here.

info Fetching system and libraries information...
System:
    OS: macOS 10.15.4
    CPU: (4) x64 Intel(R) Core(TM) i5-6267U CPU @ 2.90GHz
    Memory: 108.54 MB / 8.00 GB
    Shell: 5.7.1 - /bin/zsh
  Binaries:
    Node: 12.16.3 - /usr/local/bin/node
    Yarn: 1.22.4 - /usr/local/bin/yarn
    npm: 6.14.4 - /usr/local/bin/npm
    Watchman: 4.9.0 - /usr/local/bin/watchman
  Managers:
    CocoaPods: 1.9.1 - /usr/local/bin/pod
  SDKs:
    iOS SDK:
      Platforms: iOS 13.5, DriverKit 19.0, macOS 10.15, tvOS 13.4, watchOS 6.2
    Android SDK:
      API Levels: 23, 26, 28, 29
      Build Tools: 28.0.3, 29.0.2
      Android NDK: Not Found
  IDEs:
    Android Studio: 4.0 AI-193.6911.18.40.6626763
    Xcode: 11.5/11E608c - /usr/bin/xcodebuild
  Languages:
    Java: 1.8.0_121 - /usr/bin/javac
    Python: 2.7.15 - /Library/Frameworks/Python.framework/Versions/2.7/bin/python
  npmPackages:
    @react-native-community/cli: Not Found
    react: 16.13.1 => 16.13.1 
    react-native: 0.63.1 => 0.63.1 
  npmGlobalPackages:
    *react-native*: Not Found

Steps To Reproduce

  • Render a <TextInput value={this.state.value}> somewhere.
  • Type something on an ipad simulator/device
  • Observe the undo/redo buttons flashing

Expected Results

Either undo/redo should not be possible, or it should behave just as if a native input was used (do not clear the stack after each component update)

Snack, code example, screenshot, or link to a repository:

The issue can be observed even with the sample code from the docs:

import React, { Component } from 'react';
import { TextInput } from 'react-native';

const UselessTextInput = () => {
  const [value, onChangeText] = React.useState('Useless Placeholder');

  return (
    <TextInput
      style={{ height: 40, borderColor: 'gray', borderWidth: 1 }}
      onChangeText={text => onChangeText(text)}
      value={value}
    />
  );
}

export default UselessTextInput;

Additionally, the following crash will happen from time to time, presumably from this poor undo/redo handling of the component, or even Apple's source code.

EXC_BAD_ACCESS Attempted to dereference garbage pointer 0x105c3fa0. 
    /usr/lib/libobjc.A.dylib _objc_msgSend
    Frameworks/Foundation.framework/Foundation -[_NSUndoStack popAndInvoke]
    Frameworks/Foundation.framework/Foundation -[NSUndoManager undoNestedGroup]
    PrivateFrameworks/UIKitCore.framework/UIKitCore ___58-[UIApplication _showEditAlertViewWithUndoManager:window:]_block_invoke_2.2401
    PrivateFrameworks/UIKitCore.framework/UIKitCore +[UIUndoGestureInteraction presentProductivityGestureTutorialIfNeededWithCompletion:]
    PrivateFrameworks/UIKitCore.framework/UIKitCore ___58-[UIApplication _showEditAlertViewWithUndoManager:window:]_block_invoke.2400
    PrivateFrameworks/UIKitCore.framework/UIKitCore -[UIAlertController _invokeHandlersForAction:]
    PrivateFrameworks/UIKitCore.framework/UIKitCore ___103-[UIAlertController _dismissAnimated:triggeringAction:triggeredByPopoverDimmingView:dismissCompletion:]_block_invoke.458
    PrivateFrameworks/UIKitCore.framework/UIKitCore -[UIPresentationController transitionDidFinish:]
    PrivateFrameworks/UIKitCore.framework/UIKitCore ___56-[UIPresentationController runTransitionForCurrentState]_block_invoke.503
    PrivateFrameworks/UIKitCore.framework/UIKitCore -[_UIViewControllerTransitionContext completeTransition:]
    PrivateFrameworks/UIKitCore.framework/UIKitCore -[UIViewAnimationBlockDelegate _didEndBlockAnimation:finished:context:]
    PrivateFrameworks/UIKitCore.framework/UIKitCore -[UIViewAnimationState sendDelegateAnimationDidStop:finished:]
    PrivateFrameworks/UIKitCore.framework/UIKitCore -[UIViewAnimationState animationDidStop:finished:]
    PrivateFrameworks/UIKitCore.framework/UIKitCore -[UIViewAnimationState animationDidStop:finished:]
    Frameworks/QuartzCore.framework/QuartzCore CA::Layer::run_animation_callbacks(void*)
    /usr/lib/system/libdispatch.dylib __dispatch_client_callout
    /usr/lib/system/libdispatch.dylib __dispatch_main_queue_callback_4CF$VARIANT$armv81
    Frameworks/CoreFoundation.framework/CoreFoundation ___CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__
    Frameworks/CoreFoundation.framework/CoreFoundation ___CFRunLoopRun
    Frameworks/CoreFoundation.framework/CoreFoundation _CFRunLoopRunSpecific
    PrivateFrameworks/GraphicsServices.framework/GraphicsServices _GSEventRunModal
    PrivateFrameworks/UIKitCore.framework/UIKitCore _UIApplicationMain
    zinspector3 _mh_execute_header
    /usr/lib/system/libdyld.dylib _start

Sample video:
react native undo bug

@mhoran
Copy link
Contributor

mhoran commented Sep 25, 2020

I was able to work around this issue by creating a custom component as shown below, but it would great to see a proper fix for this.

import * as React from 'react';
import { TextInput } from 'react-native';

type Props = React.ComponentProps<typeof TextInput>;

const UndoTextInput: React.FC<Props> = ({ value, onChangeText, ...rest }) => {
  const lastValue = React.useRef<string>();
  const textInput = React.useRef<TextInput>(null);

  const handleChangeText = (textValue: string) => {
    lastValue.current = textValue;
    onChangeText && onChangeText(textValue);
  };

  React.useEffect(() => {
    if (value !== lastValue.current) {
      lastValue.current = value;
      textInput.current?.setNativeProps({ text: value });
    }
  }, [value]);

  return (
    <TextInput {...rest} ref={textInput} onChangeText={handleChangeText} />
  );
};

export default UndoTextInput;

@cristianoccazinsp
Copy link
Contributor Author

We are already using a UI library that wraps TextInput, so using the above doesn't really work for us.

@stale
Copy link

stale bot commented Dec 25, 2020

Hey there, it looks like there has been no activity on this issue recently. Has the issue been fixed, or does it still require the community's attention? This issue may be closed if no further activity occurs. You may also label this issue as a "Discussion" or add it to the "Backlog" and I will leave it open. Thank you for your contributions.

@stale stale bot added the Stale There has been a lack of activity on this issue and it may be closed soon. label Dec 25, 2020
@mhoran
Copy link
Contributor

mhoran commented Dec 25, 2020

This is still an issue.

@stale stale bot removed the Stale There has been a lack of activity on this issue and it may be closed soon. label Dec 25, 2020
@MrAlexWeber
Copy link

I'm also seeing the occasional EXC_BAD_ACCESS "Attempted to dereference garbage pointer" error. @mhoran or someone please add the discussion label so that the stale-bot won't close this issue!

@github-actions
Copy link

This issue is stale because it has been open 180 days with no activity. Remove stale label or comment or this will be closed in 7 days.

@github-actions github-actions bot added the Stale There has been a lack of activity on this issue and it may be closed soon. label Jun 20, 2023
@mhoran
Copy link
Contributor

mhoran commented Jun 20, 2023

Still an issue.

@github-actions github-actions bot removed the Stale There has been a lack of activity on this issue and it may be closed soon. label Jun 21, 2023
Copy link

This issue is stale because it has been open 180 days with no activity. Remove stale label or comment or this will be closed in 7 days.

@github-actions github-actions bot added the Stale There has been a lack of activity on this issue and it may be closed soon. label Dec 18, 2023
@mhoran
Copy link
Contributor

mhoran commented Dec 18, 2023

Confirmed still an issue but the workaround continues to work. Perhaps the fix for #27693 as proposed by @gedu in #39385 will help, but I'm not sure.

@github-actions github-actions bot removed the Stale There has been a lack of activity on this issue and it may be closed soon. label Dec 19, 2023
@mhoran
Copy link
Contributor

mhoran commented Feb 19, 2024

This is still an issue in react-native 0.73.4 / Expo v50. In addition, the workaround posted above needed value added as a dependency to useEffect to resolve a race condition.

mhoran added a commit to mhoran/weechatRN that referenced this issue Feb 28, 2024
The hostname TextInput also suffers from
facebook/react-native#29572.
@gedu
Copy link

gedu commented Mar 1, 2024

This is how my fix looks like.

Seems that it fix the issue, if you can ping and make my PR more visible so it can be review and merged will be awesome.

If the steps I made aren't correct pleas send it again. I use the value and onChange props.

TextInput_with_fix_undo_test.mp4

@react-native-bot
Copy link
Collaborator

This issue is stale because it has been open 180 days with no activity. Remove stale label or comment or this will be closed in 7 days.

@react-native-bot react-native-bot added the Stale There has been a lack of activity on this issue and it may be closed soon. label Aug 29, 2024
@mhoran
Copy link
Contributor

mhoran commented Aug 29, 2024

Still an issue.

@gedu
Copy link

gedu commented Aug 29, 2024

I'm proposing another solution: #39385 (comment)

@mhoran
Copy link
Contributor

mhoran commented Oct 27, 2024

This looks to still be an issue in 0.76.0 on New Arch with #46970 applied.

@mhoran
Copy link
Contributor

mhoran commented Oct 29, 2024

This issue is fixed by the three patches mentioned in reactwg/react-native-releases#595 (comment). Those should make it into 0.76 once the pick request is complete. To test sooner, you can apply the patches to 0.76.0 via patch-package as shown in this reproducer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Component: TextInput Related to the TextInput component. Platform: iOS iOS applications.
Projects
None yet
Development

No branches or pull requests

7 participants