facebook / react-native

A framework for building native applications using React
https://reactnative.dev
MIT License
117.1k stars 24.07k forks source link

`maxLength` of TextInput does not work when value is changed after state update #44965

Open kunalchavhan opened 3 weeks ago

kunalchavhan commented 3 weeks ago

Description

maxLength of Text Input is not working when value is changed after state update. It works as expected when input is given with keyboard. <TextInput style={styles.textInput} value={description} maxLength={10} onChangeText={text => setDescription(text)} />

Steps to reproduce

  1. Set maxLength of TextInput to any non zero number
  2. Store any text in state
  3. Use text stored in state as value in TextInput
  4. Update the state with text length greater than maxLength
  5. TextInput will have text which has length greater than given maxLength

React Native Version

0.74.2

Affected Platforms

Runtime - iOS

Output of npx react-native info

System:
  OS: macOS 13.5.1
  CPU: (10) arm64 Apple M1 Max
  Memory: 73.36 MB / 32.00 GB
  Shell:
    version: "5.9"
    path: /bin/zsh
Binaries:
  Node:
    version: 18.12.0
    path: ~/.nvm/versions/node/v18.12.0/bin/node
  Yarn:
    version: 3.6.4
    path: /opt/homebrew/bin/yarn
  npm:
    version: 8.19.2
    path: ~/.nvm/versions/node/v18.12.0/bin/npm
  Watchman: Not Found
Managers:
  CocoaPods:
    version: 1.14.3
    path: /Users/kunal.chavhan/.rvm/gems/ruby-3.2.2/bin/pod
SDKs:
  iOS SDK:
    Platforms:
      - DriverKit 23.0
      - iOS 17.0
      - macOS 14.0
      - tvOS 17.0
      - watchOS 10.0
  Android SDK: Not Found
IDEs:
  Android Studio: Jellyfish 2023.3.1 Patch 2 Jellyfish 2023.3.1 Patch 2
  Xcode:
    version: 15.0/15A240d
    path: /usr/bin/xcodebuild
Languages:
  Java:
    version: 17.0.10
    path: /usr/bin/javac
  Ruby:
    version: 3.2.2
    path: /Users/kunal.chavhan/.rvm/rubies/ruby-3.2.2/bin/ruby
npmPackages:
  "@react-native-community/cli": Not Found
  react:
    installed: 18.2.0
    wanted: 18.2.0
  react-native:
    installed: 0.74.2
    wanted: 0.74.2
  react-native-macos: Not Found
npmGlobalPackages:
  "*react-native*": Not Found
Android:
  hermesEnabled: true
  newArchEnabled: false
iOS:
  hermesEnabled: true
  newArchEnabled: false

Stacktrace or Logs

NA

Reproducer

https://github.com/kunalchavhan/rn-textinput-maxlength-reproducer

Screenshots and Videos

https://github.com/facebook/react-native/assets/61144478/4a377ec3-e60a-46ad-b54d-c6362ebd8622

kunalchavhan commented 3 weeks ago

I was debugging this and found that this method is getting called whenever text is updated from react's state change. This method then calls setAttributedString which then sets the text. I could not find any checks here for maxLength prop.

When input is received from keyboard this method is called which has maxLength prop check.

Any reason for not checking maxLength prop here also?

kunalchavhan commented 2 weeks ago

@sammy-SC could you please take a look into this? Thank you for your time.

sammy-SC commented 1 week ago

I was debugging this and found that this method is getting called whenever text is updated from react's state change. This method then calls setAttributedString which then sets the text. I could not find any checks here for maxLength prop.

When input is received from keyboard this method is called which has maxLength prop check.

Any reason for not checking maxLength prop here also?

The code you are linking is for the new architecture but your repro is with the old architecture. For the old architecture, maxLength is handled here. It appears maxLength is not taken account for when the update comes from React.

This can be annoying but there is a simple workaround if this is blocking you. When setting text from React, you can check for the length of new text value and shorten it if it goes over the maxLength. maxLength is important for the updates to TextInput coming from native, because there your JavaScript code doesn't have a a chance to run. Thanks to maxLength prop, you have a chance to prevent iOS from painting TextInput with value that is longer than maxLength.

kunalchavhan commented 1 week ago

The code you are linking is for the new architecture but your repro is with the old architecture. For the old architecture, maxLength is handled here. It appears maxLength is not taken account for when the update comes from React.

This can be annoying but there is a simple workaround if this is blocking you. When setting text from React, you can check for the length of new text value and shorten it if it goes over the maxLength. maxLength is important for the updates to TextInput coming from native, because there your JavaScript code doesn't have a a chance to run. Thanks to maxLength prop, you have a chance to prevent iOS from painting TextInput with value that is longer than maxLength.

Thank you for the clarification and sorry for wrong linking of code. I pushed repro for new architecture here.

Thank you for suggesting workaround. I have checked that the maxLength prop works for updates from React on android. Would it be possible to have the same behaviour on iOS also?

kunalchavhan commented 1 week ago

Thank you for the clarification and sorry for wrong linking of code. I pushed repro for new architecture here.

Thank you for suggesting workaround. I have checked that the maxLength prop works for updates from React on android. Would it be possible to have the same behaviour on iOS also?

@sammy-SC if you agree that iOS should handle maxLength on updates from react, can I try to resolve this?