0

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)

0

2 Answers 2

1

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;
Sign up to request clarification or add additional context in comments.

2 Comments

i'm trying to understand,can we solve this issue without moving newItem variable to state ?
You can make use of a uncontrolled input and get rid of onChange event. One you do that you can read the value of input using ref
0

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;

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.