mr.abdo
mr.abdo

Reputation: 485

How to deal with multiple input components in react

I'm coding a functionality like to do task app, so the user can insert multiples taks. That's a print of the system screen so far.

enter image description here

I passed hours trying to figure it out how to deal with each input text individually, including trying to implement similar solutions from stackoverflow.

export default class Task extends Component {
  constructor(props) {
    super(props)
    this.state = { cardID: '', description: '', list: [] }

    this.handleAdd = this.handleAdd.bind(this)
    this.handleChange = this.handleChange.bind(this)
    this.handleEdit = this.handleEdit.bind(this)       
    this.refresh()
  }
  handleAdd = cardID => {
    axios({
      method: 'post',
      url: URL,
      data: {
        description: this.state.description,
        cardID: cardID
      }
    }).then(resp => this.refresh())
  }

  handleChange(e) {
    this.setState({ ...this.state, description: e.target.value})
  }

  handleEdit = Task => {
    axios.put(`${URL}/${Task._id}`, Task)
      .then(resp => this.refresh(this.state.description))
  }

  refresh() {
    axios.get(`${URL}?sort=createdAt`)
      .then(resp => this.setState({ ...this.state, description: '', list: resp.data }))
  }

  render() {
    return (
      <Fragment>
          <TaskCard title="Parceiros Chave" cardID='1' color='blue-violet'
            handleAdd={this.handleAdd}
            handleChange={this.handleChange}       
            handleEdit={this.handleEdit}
            description={this.state.description}
            list={this.state.list}
          />
        ....
      </Fragment >
    )
  }
}

That's my taskCard component

const TaskCard = props => {

  const renderRows = () => {
    const list = props.list || []
    return list.map(Task => (
      Task.cardID === props.cardID &&      
      <Form key={Task._id}>
        <Form.Group key={Task._id} controlId="formBasicEmail">
          <Form.Control key={Task._id} className='inputs-field' name={Task._id} type="text"
            value={props.list.find(x => x._id === Task._id).description}
            onKeyPress={event => {
              if (event.key === 'Enter') {
                props.handleEdit(Task)
                event.preventDefault()
              }
            }}            
          />          
        </Form.Group>
      </Form>      
    ))
  }

  return (
    <Fragment>
      <Col style={{ padding: '0px' }}>

        <Card className={props.class}>
          <Card.Body style={{ margin: '0px' }}>
            <Card.Title className={props.color}>{props.title}</Card.Title>
            {renderRows()}
            <Form>
              <Form.Group controlId="formBasicEmail">
                <Form.Control className='input-field' name={'description' + props.cardID} type="text" placeholder="Insira um registro"
                  value={props.description}
                  onChange={props.handleChange}
                  onKeyPress={event => {
                    if (event.key === 'Enter') {
                      props.handleAdd(props.cardID)
                      event.preventDefault()
                    }
                  }}
                />
              </Form.Group>
            </Form>
          </Card.Body>
        </Card>
      </Col>
    </Fragment >
  )
}

export default TaskCard

I'm using only description to deal with all input field.

list array contains all the input values that comes from mongodb. In my example, that's the list array content:

enter image description here

For example, how can I edit one input field value without affect the other one?

Upvotes: 0

Views: 575

Answers (1)

Travis James
Travis James

Reputation: 1939

If you want to keep the state for all inputs in the parent component you need to have a state value for each individual input.

handleChange(e) {
    this.setState({ ...this.state, description: e.target.value})
  }

Is just overwriting any prior input value saved to state.

You need to do something like this:

state = {}

handleChange(e) {
    this.setState({ ...this.state, [e.target.name]: e.target.value})
  }

So that each input has it's own value in the parent state

Upvotes: 3

Related Questions