GN.
GN.

Reputation: 9909

Initializing React number input control with blank value?

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"
/>

Upvotes: 35

Views: 32272

Answers (5)

kmui2
kmui2

Reputation: 2537

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 ?? ''}
/>

Upvotes: 3

GetSwifty
GetSwifty

Reputation: 377

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

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

Upvotes: 16

Hady
Hady

Reputation: 2674

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: '',
}

Upvotes: -2

Nishant
Nishant

Reputation: 797

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

Upvotes: 3

Stefan
Stefan

Reputation: 175

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
}

Upvotes: -1

Related Questions