0

Here's my code:

import React, { Component } from 'react'
import classnames from 'classnames'

class TodoTextInput extends Component {
  state = {
    text: this.props.text
  }

  handleSubmit = e => {
    const text = e.target.value.trim()
    if (e.which === 13) {
      this.props.onSave(text)
      this.setState({
        text: ''
      })
    }
  }

  handleChange = e => {
    this.setState({
      text: e.target.value
    })
  }

  handleBlur = e => {
    if (!this.props.newTodo) {
      this.props.onSave(e.target.value)
    }
  }

  render() {
    return (
      <input className={
             classnames({
               edit: this.props.editing,
               'new-todo': this.props.newTodo
               })
             }
             type='text'
             autoFocus='true'
             value={this.state.text}
             onChange={this.handleChange}
             placeholder={this.props.placeholder}
             onKeyDown={this.handleSubmit} />
    )
  }
}

export default TodoTextInput

When I run this code and start typing in the input field, I get the following error message in the console:

Warning: A component is changing an uncontrolled input of type text to be controlled.

This leads me to believe that the value attribute sees this.state.text as null or undefined. However, the code works when I add || ' ' at the end of state.text to become:

text: this.props.text || ''

I have two questions:

  1. Why does it work even though ' ' should translate to falsy too just like this.props.text?

  2. Why does the value attribute see this.props.text as null or undefined?

1 Answers1

1

The initial value of this.state.text is undefined (meaning this.props.text has been undefined). If the value prop of input is undefined, React considers the input as "uncontrolled".

You should fall back to empty string in the state initialization

state = {
  text: this.props.text || ''
}

to fix this or assign a default value to TodoTextInput

TodoTextInput.defaultProps = {
  text: ''
}
lipp
  • 5,586
  • 1
  • 21
  • 32