React/Redux Redux-Form Pre-Populate Form For Updat

2019-06-27 16:53发布

问题:

I'm trying to pre-populate a form using the redux-form library. The issues I'm having now is being able to pass (perhaps) the item.id from the Items or Item component to the List when the Edit Item button is clicked. That way I could check it against my listItems array and grab it's data to populate the form. But prior to doing this, I created a function populateForm to try redux-form's dispatch/initialize function for "populating" the form. It works as expected, except that when I click Add Item the form never resets. I basically need two things done.

  1. Get the logic going for selecting a single item and get it's data populated in the form so it can be edited.
  2. figure why the form doesn't reset after it's populated on Edit Item click.

Thanks in advance.

/components/List.jsx

export class List extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      isModalOpen: false
    }

    this.resetFrom = this.resetForm.bind(this)
  }

  toggleModal () {
    this.setState({ isModalOpen: !this.state.isModalOpen })
  }

  deleteList (listId, e) {
    e.stopPropagation()

    this.props.listActions.deleteList(listId)
  }

  resetForm() {
    this.props.reset('items')
  }

  createItem (item) {
    let items = {
      id: uuid.v4(),
      sku: item.sku,
      text: item.text,
      price: item.price
    }

    this.props.itemActions.createItem(items) 
    this.props.listActions.connectToList(this.props.list.id, items.id)
    this.resetForm()
  }
  // UPDATED
  populateForm (item) {
    const { id, sku, text, price } = item
    this.props.dispatch(initialize('items', {
      id, sku, text, price
    }, ['id', 'sku', 'text', 'price']))
  }
  // WAS THIS
  //populateForm () {
     //this.props.dispatch(initialize('items', {
      //sku: "Stuff",
      //text: "blah", 
      //price: "this"
    //}, ['sku', 'text', 'price']))
  //}

  render () {
    const { list, ...props } = this.props
    const listId = list.id

    return (
      <div {...props}>
        <div className='list-add-item'>
          <button onClick={this.toggleModal.bind(this, listId)}>+</button>
        </div>

        <div className='list-header'
          onClick={() => props.listActions.updateList({id: listId, isEditing: true})} >

          <Editor
            className='list-title'
            isEditing={list.isEditing}
            value={list.title}
            onEdit={(title) => props.listActions.updateList({id: listId, title, isEditing: false})}>
          </Editor>

          <div className='list-delete'>
            <button onClick={this.deleteList.bind(this, listId)}>x</button>
          </div>
        </div>

        <Items 
          items={props.listItems}
          // UPDATED
          populateForm={(item) => this.populateForm(item)}
          // WAS THIS
          // populateForm={(id) => this.populateForm({id, isEditing: true})}
          openModal={this.toggleModal.bind(this)}>
        </Items>

        <Modal 
          className='list-add-item'
          openModal={this.state.isModalOpen}>
          // UPDATED
          <ItemForm
            onEdit={this.props.itemActions.updateItem}
            onSubmit={this.createItem.bind(this)}>
          </ItemForm>
          // WAS THIS
          // <ItemForm onSubmit={this.createItem.bind(this)}/>
        </Modal>
      </div>
    )
  }
}

function mapStateToProps (state, props) {
  return {
    lists: state.lists,
    listItems: props.list.items.map((id) => state.items[
        state.items.findIndex((item) => item.id === id)
    ]).filter((item) => item)
  }
}

function mapDispatchToProps (dispatch) {
  return {
    listActions: bindActionCreators(listActionCreators, dispatch),
    itemActions: bindActionCreators(itemActionCreators, dispatch),
    reset: bindActionCreators(reset, dispatch),
    dispatch: bindActionCreators(dispatch, dispatch)
  }
}

const { string, arrayOf, shape } = React.PropTypes

List.propTypes = {
  lists: arrayOf(shape({
    id: string.isRequired,
    title: string.isRequired
  }).isRequired)
}

export default connect(mapStateToProps, mapDispatchToProps)(List)

/components/Items.jsx

export default class Items extends React.Component {
  render () {
    const {items, openModal, populateForm, ...props} = this.props

    return (
      <ul className='items'>{items.map((item) =>
        <Item
          className='item'
          key={item.id}
          id={item.id}
          sku={item.sku}
          text={item.text}
          price={item.price}
          // UPDATED
          populateForm={populateForm.bind(null, item)}
          // WAS THIS
          // populateForm={populateForm.bind(this)}
          openModal={openModal}>
        </Item>
      )}</ul>
    )
  }
}

/components/Item.jsx

export default class Item extends React.Component {
  render () {
    const { openModal, populateForm, ...props } = this.props
    return (
      <span>
        <li>SKU: {this.props.sku}</li>  
        <li>ITEM: {this.props.text}</li>
        <li>PRICE: {this.props.price}</li>
        <button onClick={this.props.populateForm}>Edit Item</button>
      </span>
    )
  }
}

/components/ItemForm.jsx

import React from 'react'
import { reduxForm } from 'redux-form'

class ItemForm extends React.Component {
  render() {
    const { fields: {sku, text, price}, handleSubmit } = this.props

    return (
      <form onSubmit={handleSubmit} >
        <label>SKU</label>
        <input type="text" {...sku}/>

        <label>Item</label>
        <input type="text" {...text} />

        <label>Price</label>
        <input type="text" {...price} />

        <button type="submit">Add item</button>
      </form>
    )
  }
}

ItemForm = reduxForm({
  form: 'items',
  fields: ['sku', 'text', 'price']
})(ItemForm);

export default ItemForm

回答1:

There are several problems that make this code hard to follow for me. I'm not really sure what you're trying to accomplish. For example:

  • List.jsx is calling populateForm() with {id, isEditing: true}, but populateForm() doesn't take any parameters.

  • For some reason Items.jsx is binding populateForm to this. Why?

  • Item.jsx is passing populateForm directly to onClick, so its parameter is going to be the event.

  • ItemForm.jsx, in contrast, is flawless.