question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

TextInput controlled/uncontrolled component warnings

See original GitHub issue

Current behaviour

Internally TextInput seems to always be passing a value to the native view Passing a defaultValue prop would raise the following warnings (only on react-native-web) though

Warning: TextInput contains an input of type text with both value and defaultValue props. Input elements must be either controlled or uncontrolled (specify either the value prop, or the defaultValue prop, but not both). Decide between using a controlled or uncontrolled input element and remove one of these props. More info: https://reactjs.org/link/controlled-components

Warning: A component is changing an uncontrolled input to be controlled. This is likely caused by the value changing from undefined to a defined value, which should not happen. Decide between using a controlled or uncontrolled input element for the lifetime of the component. More info: https://reactjs.org/link/controlled-components

Expected behaviour

Support uncontrolled inputs

I want to use a TextInput without passing the value prop. I might pass a defaultValue: https://reactnative.dev/docs/textinput#defaultvalue

Useful for use-cases where you do not want to deal with listening to events and updating the value prop to keep the controlled state in sync.

Code sample

https://snack.expo.dev/@kidroca/paper-uncontrolled-text-input https://snack.expo.io/@kidroca/paper-uncontrolled-text-input

  • it seems the warning does not appear in the snack’s console
  • for me the warning appears in the browser (I use react-native-web)

What have you tried

It seems it happens due to the ...rest spread here, when rest contains defaultValue it would be spread to the underlying element

https://github.com/callstack/react-native-paper/blob/58851e3376430b8c4278faa38f5b43339743784d/src/components/TextInput/TextInput.tsx#L437-L439

  • when both value and defaultValue are defined react seems to be raising a warning

A workaround that I currently use is to use the render prop and render the react-native TextInput without passing the value

Could we maybe not pass the value down to the native field if we don’t have to? The value is updated per each text change

https://github.com/callstack/react-native-paper/blob/58851e3376430b8c4278faa38f5b43339743784d/src/components/TextInput/TextInput.tsx#L376-L381

When we don’t pass the value down to the native field? This way we carry less updates back and forth and have better performance. We can still keep it in local state to react to it’s changes

Your Environment

software version
ios or android iOS 15.0.2
react-native 0.65.1
react-native-web ^0.17.1
react-native-paper ^4.9.2
node v14.18.1
npm or yarn npm v6.14.15
expo sdk n/a

Issue Analytics

  • State:open
  • Created 2 years ago
  • Reactions:1
  • Comments:5 (3 by maintainers)

github_iconTop GitHub Comments

1reaction
SleeplessBytecommented, Mar 18, 2022

Here is the patch-package patch as workaround. All it does is not apply value if defaultValue is present:

Object.prototype.hasOwnProperty.call(rest, 'defaultValue') ? undefined : this.state.value

Save as patches/react-native-paper+4.11.2.patch. Feel free to turn this into a PR and take credit.

diff --git a/node_modules/react-native-paper/lib/commonjs/components/TextInput/TextInput.js b/node_modules/react-native-paper/lib/commonjs/components/TextInput/TextInput.js
index 6a28b61..019acbf 100644
--- a/node_modules/react-native-paper/lib/commonjs/components/TextInput/TextInput.js
+++ b/node_modules/react-native-paper/lib/commonjs/components/TextInput/TextInput.js
@@ -346,7 +346,7 @@ class TextInput extends React.Component {
       ...rest
     } = this.props;
     return mode === 'outlined' ? /*#__PURE__*/React.createElement(_TextInputOutlined.default, _extends({}, rest, {
-      value: this.state.value,
+      value: Object.prototype.hasOwnProperty.call(rest, 'defaultValue') ? undefined : this.state.value,
       parentState: this.state,
       innerRef: ref => {
         this.root = ref;
@@ -359,7 +359,7 @@ class TextInput extends React.Component {
       onLeftAffixLayoutChange: this.onLeftAffixLayoutChange,
       onRightAffixLayoutChange: this.onRightAffixLayoutChange
     })) : /*#__PURE__*/React.createElement(_TextInputFlat.default, _extends({}, rest, {
-      value: this.state.value,
+      value: Object.prototype.hasOwnProperty.call(rest, 'defaultValue') ? undefined : this.state.value,
       parentState: this.state,
       innerRef: ref => {
         this.root = ref;
diff --git a/node_modules/react-native-paper/lib/module/components/TextInput/TextInput.js b/node_modules/react-native-paper/lib/module/components/TextInput/TextInput.js
index aee53ef..e21a31d 100644
--- a/node_modules/react-native-paper/lib/module/components/TextInput/TextInput.js
+++ b/node_modules/react-native-paper/lib/module/components/TextInput/TextInput.js
@@ -321,7 +321,7 @@ class TextInput extends React.Component {
       ...rest
     } = this.props;
     return mode === 'outlined' ? /*#__PURE__*/React.createElement(TextInputOutlined, _extends({}, rest, {
-      value: this.state.value,
+      value: Object.prototype.hasOwnProperty.call(rest, 'defaultValue') ? undefined : this.state.value,
       parentState: this.state,
       innerRef: ref => {
         this.root = ref;
@@ -334,7 +334,7 @@ class TextInput extends React.Component {
       onLeftAffixLayoutChange: this.onLeftAffixLayoutChange,
       onRightAffixLayoutChange: this.onRightAffixLayoutChange
     })) : /*#__PURE__*/React.createElement(TextInputFlat, _extends({}, rest, {
-      value: this.state.value,
+      value: Object.prototype.hasOwnProperty.call(rest, 'defaultValue') ? undefined : this.state.value,
       parentState: this.state,
       innerRef: ref => {
         this.root = ref;
diff --git a/node_modules/react-native-paper/src/components/TextInput/TextInput.tsx b/node_modules/react-native-paper/src/components/TextInput/TextInput.tsx
index 4641c34..26c8bcd 100644
--- a/node_modules/react-native-paper/src/components/TextInput/TextInput.tsx
+++ b/node_modules/react-native-paper/src/components/TextInput/TextInput.tsx
@@ -444,7 +444,7 @@ class TextInput extends React.Component<TextInputProps, State> {
     return mode === 'outlined' ? (
       <TextInputOutlined
         {...rest}
-        value={this.state.value}
+        value={Object.prototype.hasOwnProperty.call(rest, 'defaultValue') ? undefined : this.state.value}
         parentState={this.state}
         innerRef={(ref) => {
           this.root = ref;
@@ -460,7 +460,7 @@ class TextInput extends React.Component<TextInputProps, State> {
     ) : (
       <TextInputFlat
         {...rest}
-        value={this.state.value}
+        value={Object.prototype.hasOwnProperty.call(rest, 'defaultValue') ? undefined : this.state.value}
         parentState={this.state}
         innerRef={(ref) => {
           this.root = ref;
0reactions
SleeplessBytecommented, May 6, 2022

In 4.12.x new errors were introduced, which require a different patch.

// Use value from props instead of local state when input is controlled
const value = isControlled ? rest.value : uncontrolledValue;

// ...
<TextInputComponent
   // ...
   {...rest}
   value={value}
   // ...
/>

This incorrect assigns value when the component is uncontrolled.

Save as patches/react-native-paper+4.12.1.patch., delete the previous one.

diff --git a/node_modules/react-native-paper/lib/commonjs/components/TextInput/TextInput.js b/node_modules/react-native-paper/lib/commonjs/components/TextInput/TextInput.js
index 04a7c0f..887d2da 100644
--- a/node_modules/react-native-paper/lib/commonjs/components/TextInput/TextInput.js
+++ b/node_modules/react-native-paper/lib/commonjs/components/TextInput/TextInput.js
@@ -293,7 +293,7 @@ const TextInput = /*#__PURE__*/React.forwardRef((_ref, ref) => {
       editable: editable,
       render: render
     }, rest, {
-      value: value,
+      value: isControlled ? value : undefined,
       parentState: {
         labeled,
         error,
@@ -326,7 +326,7 @@ const TextInput = /*#__PURE__*/React.forwardRef((_ref, ref) => {
     editable: editable,
     render: render
   }, rest, {
-    value: value,
+    value: isControlled ? value : undefined,
     parentState: {
       labeled,
       error,
diff --git a/node_modules/react-native-paper/lib/module/components/TextInput/TextInput.js b/node_modules/react-native-paper/lib/module/components/TextInput/TextInput.js
index 4a4fb51..711129c 100644
--- a/node_modules/react-native-paper/lib/module/components/TextInput/TextInput.js
+++ b/node_modules/react-native-paper/lib/module/components/TextInput/TextInput.js
@@ -273,7 +273,7 @@ const TextInput = /*#__PURE__*/React.forwardRef((_ref, ref) => {
       editable: editable,
       render: render
     }, rest, {
-      value: value,
+      value: isControlled ? value : undefined,
       parentState: {
         labeled,
         error,
@@ -306,7 +306,7 @@ const TextInput = /*#__PURE__*/React.forwardRef((_ref, ref) => {
     editable: editable,
     render: render
   }, rest, {
-    value: value,
+    value: isControlled ? value : undefined,
     parentState: {
       labeled,
       error,
diff --git a/node_modules/react-native-paper/src/components/TextInput/TextInput.tsx b/node_modules/react-native-paper/src/components/TextInput/TextInput.tsx
index 2fc72d4..bcc4753 100644
--- a/node_modules/react-native-paper/src/components/TextInput/TextInput.tsx
+++ b/node_modules/react-native-paper/src/components/TextInput/TextInput.tsx
@@ -403,7 +403,7 @@ const TextInput = React.forwardRef<TextInputHandles, TextInputProps>(
           editable={editable}
           render={render}
           {...rest}
-          value={value}
+          value={isControlled ? value : undefined}
           parentState={{
             labeled,
             error,
@@ -438,7 +438,7 @@ const TextInput = React.forwardRef<TextInputHandles, TextInputProps>(
         editable={editable}
         render={render}
         {...rest}
-        value={value}
+        value={isControlled ? value : undefined}
         parentState={{
           labeled,
           error,
Read more comments on GitHub >

github_iconTop Results From Across the Web

React a component is changing an uncontrolled input of type ...
If your state is initialized with props.value being null React will consider your Checkbox component to be uncontrolled.
Read more >
Uncontrolled Components - React
In React, an <input type="file" /> is always an uncontrolled component because its value can only be set by a user, and not...
Read more >
A component is changing an uncontrolled input to be controlled
In this tutorial, we will learn why this warning occurs and how to solve it. Consider the following component: App.js.
Read more >
warning: a component is changing a controlled input to be ...
A component is changing an uncontrolled input to be controlled - CodingDeft. Codingdeft.com > posts > react-controlled-uncontrolled. Source code. If you are ...
Read more >
A component is changing an uncontrolled input to be controlled
To fix the warning, initialize the input value to an empty string, e.g. value={message || ''} . component changing uncontrolled input. Here is...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found