35

I'd like my controlled input to initialize with no value in the box. The input is a number, so I don't pass in an empty ''. Using defaultProps, I initialize the input with a null.

When typing into the input the console reports this message:

<MyInput> is changing an uncontrolled input of type number to be controlled. Input elements should not switch from uncontrolled to controlled (or vice versa).

To prevent this normally I initialize with an empty string to prevent this "switching" from happening. But with a number (I don't want to show a 0, I want nothing to show) I am not sure how to do it.

static defaultProps = {
    estimatedHours: null,
    estimatedMinutes: null,
  }

defalut values ^^

<input
   type="number"
   onChange={(e) => this.handleChange('Hours', e.target.value)}
   onKeyDown={this.handleKeyDown}
   onPaste={this.handlePaste}
   value={estimatedHours}
   placeholder={hoursText}
   className="slds-input th-trailmix-textbox th-time-component__input"
/>
4
  • Can you share the uncontrolled input component code? Commented Dec 4, 2017 at 21:48
  • Can't seem to replicate this? Which version of React are you using? Commented Dec 4, 2017 at 21:58
  • Using React 15.6.1 Commented Dec 4, 2017 at 22:40
  • Use defaultValue and onBlur combination. Commented Dec 5, 2017 at 22:21

5 Answers 5

16

Simpler approach is to have a fallback value be an empty string. Works for type=number as well.

<input type="number" value={estimatedHours || ''} />
Sign up to request clarification or add additional context in comments.

2 Comments

Note that if estimatedHours is 0, it'll fallback to the empty string. To avoid this, either use the ternary operator or use the nullish coalescing operator typescriptlang.org/docs/handbook/release-notes/….
+1 for the comment on using nullish coalescing operator since if a value starts as either null or undefined you get the warning about a uncontrolled input switching to controlled. Thus the following works nicely: value={estimatedHours ?? ''}
3

You can set value Undefined,

Also add a check for input type if required

class Input extends React.Component {

    constructor(props) {
        super(props);
        this.state = {value: undefined};

        this.handleChange = this.handleChange.bind(this);
    }

    handleChange = (event) => {
        const isnum = /^\d+$/.test(event.target.value);
        if (isnum) {
            return this.setState({
                value: Number(event.target.value),
            });
        }
    };

    render() {
        return (
            <input
                type="number"
                onChange={this.handleChange}
                value={String(this.state.value)}
                placeholder={"Please enter number"}
            />
        );
    }
}

and convert String to Number and vice versa

This won't throw you an error for uncontrolled input

2 Comments

The key being the string conversion of the input value attribute. It will fail without that.
This works, but I get a warning The specified value "undefined" cannot be parsed, or is out of range. from React in the console.
3

I'd like my controlled input to initialize with no value in the box.

my problem is that I want a controlled number input with a null / undefined initial value.

I suggest defaulting the value props in the input element with an empty string like the following:

<input
   type="number"
   // ...
   value={estimatedHours === undefined ? '' : estimatedHours}
/>

This will make the input empty and prevent the warning from React. It'll also conveniently work well with the required prop too so the user must enter an input.

In TypeScript 3.7+, it can be shorted to the following using the nullish coalescing operator:

<input
   type="number"
   // ...
   value={estimatedHours ?? ''}
/>

Comments

-1

Uncontrolled inputs are simply inputs where you aren't tying value to JavaScript. So if you are rendering:

<input value={any} />

That is a controlled input.

If you want to render an uncontrolled input with an empty value you could simply write

<input type="number" /> or <input type="number" placeholder="" />
or <input type="number" placeholder="please enter a number..." />

Next, if you want to pull the value use a ref.

state = {
  query: ''
}

handleSubmit = (e) => {
  e.preventDefault()
  this.setState({ query: this.search.value })
}

render() {
  return (
    <form>
      <input 
        type="number" 
        ref={input => this.search = input} 
        placeholder="" 
      />
      <button type="submit" onClick={this.handleSubmit}>Submit</button>
    </form>
  )
}

Additionally, you can still perform logic on the return value if you need to. ie:

handleSubmit = (e) => {
  e.preventDefault()
  this.setState({ query: this.search.value.toExponential(2) })
   // square whatever the user inputs and store in this.state.query
}

4 Comments

Thanks, but my problem is that I want a controlled number input with a null / undefined initial value.
Can you elaborate on what you're trying to accomplish? In your original post you stated you wanted your _un_controlled input to initialize with no initial value. Setting the type attribute to "number" accomplishes it being a number input.
A value is passed into component X as props via Redux. Component X has a number input that uses that value. The initial value should be empty. The value should be validated as type number via propTypes
How do you want the input to use the value? Are you trying to compare what is passed to component X with what the user actually enters? If so, see this gist. Hope that makes sense. Let me know if this helps and I will edit my original answer.
-2

The easiest way to get the behaviour you are looking for is to define the prop type for this field to a string. This will allow '' to be used as a default prop. On form submission, you will need to make sure that the value of this field is parsed to a number.

type FormProps = {
  estimatedHours: string;
  estimatedMinutes: string;
}

FormProps.defaultProps = {
  estimatedHours: '',
  estimatedMinutes: '',
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.