rashidnk
rashidnk

Reputation: 4292

React.js when using non state variable Getting error as A component is changing an uncontrolled input of type text to be controlled

I'm trying to use non state variable 'newItem' to hold the input value

import React, { Component } from 'react';

class List extends Component {
  constructor() {
    super();
    this.state = { items: [1, 2] };
    this.newItem = undefined;
  }
  changeNewItem = e => {
    this.newItem = e.target.value;
    console.log(this.newItem);
  };
  addItem = e => {
    if (e.keyCode !== 13) return;
    var tmp_list = this.state.items;
    tmp_list.push(this.newItem);
    this.setState({ items: tmp_list }, () => {
      this.newItem = '';
    });
  };
  render() {
    return (
      <div>
        <ul>
          {this.state.items.map(item => (
            <li key={item}>{item}</li>
          ))}
        </ul>
        <input
          type="text"
          placeholder="add item"
          value={this.newItem}
          onChange={this.changeNewItem}
          onKeyUp={this.addItem}
        />
      </div>
    );
  }
}

export default List;

When I press enter key in textbox the item gets added to the array but getting error as below

index.js:1452 Warning: A component is changing an uncontrolled input of type text to be controlled. Input elements should not switch from uncontrolled to controlled (or vice versa). Decide between using a controlled or uncontrolled input element for the lifetime of the component. More info: in input (at List.js:29) in div (at List.js:23) in List (at App.js:9) in App (at src/index.js:8)

Upvotes: 0

Views: 396

Answers (2)

rashidnk
rashidnk

Reputation: 4292

changed to uncontrolled input and usedReact.createRef(), suggested by Comment

import React, { Component } from 'react';

class List extends Component {
  newItem;
  constructor() {
    super();
    this.state = { items: [1, 2] };
    this.input = React.createRef();
  }
  changeNewItem = e => {
    this.newItem = e.target.value;
    console.log(this.newItem);
  };
  addItem = e => {
    if (e.keyCode !== 13 || !this.newItem) return;
    var new_list = this.state.items.concat(this.newItem);
    this.setState({ items: new_list }, () => {
      this.newItem = '';
      this.input.current.value = '';
    });
  };
  render() {
    return (
      <div>
        <ul>
          {this.state.items.map(item => (
            <li key={item}>{item}</li>
          ))}
        </ul>
        <input
          type="text"
          placeholder="add item"
          ref={this.input}
          onChange={this.changeNewItem}
          onKeyUp={this.addItem}
        />
      </div>
    );
  }
}

export default List;

Upvotes: 0

Shubham Khatri
Shubham Khatri

Reputation: 281676

The problem in your case is that the initial value of the input element is undefined and then you control it using the variable this.newItem. Hence you get the warning which is trying to change an uncontrolled input to controlled.

Initialise the value to empty string instead of undefined. Also if you want the input component to change value, use state instead of a class variable

import React, { Component } from 'react';

class List extends Component {
  constructor() {
    super();
    this.state = { items: [1, 2], newItem: '' };
  }
  changeNewItem = e => {
    this.setState({newItem: e.target.value})
  };
  addItem = e => {
    if (e.keyCode !== 13) return;
    var tmp_list = this.state.items;
    tmp_list.push(this.state.newItem);
    this.setState({ items: tmp_list }, () => {
      this.state.newItem = '';
    });
  };
  render() {
    return (
      <div>
        <ul>
          {this.state.items.map(item => (
            <li key={item}>{item}</li>
          ))}
        </ul>
        <input
          type="text"
          placeholder="add item"
          value={this.state.newItem}
          onChange={this.changeNewItem}
          onKeyUp={this.addItem}
        />
      </div>
    );
  }
}

export default List;

Upvotes: 1

Related Questions