React modal 总是取 map 函数的最后一个元素

React modal always take the last element of map function

我目前正在创建一个 React todo 应用程序。所以基本上我有两个组件 TodoList 和 TodoItem

TodoList 组件将接收一个 objects 的数组,其中包含作为 属性 的标题,并通过此映射到 TodoItem 组件

在我的 TodoItem 组件中,用户可以选择编辑或删除项目。如果用户选择编辑,模式将使用文本区域显示现有标题。但是,我在实现此功能时遇到了麻烦,因为模态框将始终显示数组的最后一个元素。

待办事项列表组件

import React, { Component } from 'react'
import TodoItem from './TodoItem'
import { connect } from 'react-redux'
import { clear_todo } from '../store/actions/todoActions'

class Todolist extends Component {

  clearList = (e) => {
    e.preventDefault()
    this.props.clearList(clear_todo());
  }

  handleChange = (index, title) => {
    this.setState({
      [index]: title
    })
  }

  render() {
    const { items, editItem } = this.props.todo
    return (
      <ul className="list-group my-5">
        <h3 className="text-capitalize text-center">
          Todo List
        </h3>
        {
          items.map((item, index) => {
            const editedTitle = item.title

            return (<TodoItem key={item.id} title={item.title}
              id={item.id}
              editedTitle={editedTitle}
              onChange={this.handleChange}
              editItem={editItem} />)
          })
        }

        <button className="btn btn-danger btn-block text-capitalize mt-5" onClick={this.clearList}> Clear List </button>
      </ul>
    )
  }
}

const mapStateToProps = state => {
  return {
    todo: state.todo
  }
}

const mapDispatchToProps = dispatch => {
  return {
    clearList: (clear_todo) => { dispatch(clear_todo) }
  }
}


export default connect(mapStateToProps, mapDispatchToProps)(Todolist)

TodoItem 组件

import React, { Component } from 'react'
import { connect } from 'react-redux'
import { delete_todo, edit_todo, toggle_edit } from '../store/actions/todoActions'
import { Button, Modal, ModalHeader, ModalBody, ModalFooter, Form, FormGroup, Input } from 'reactstrap';
import TodoEditItem from './TodoEditItem'

class Todoitem extends Component {

  // constructor(props) {
  //   super(props)
  //   this.state = {
  //     [props.id]: props.title
  //   }
  // }


  handleEdit = (id, title) => {
    this.props.editTodo(edit_todo(id, title))
  }

  toggleEdit = (editItem, title) => {
    this.props.toggleEdit(toggle_edit(!editItem))
    // this.initializeTitle(title)

  }

  handleDelete = (id) => {
    this.props.deleteTodo(delete_todo(id))
  }

  // onChange = (e, id) => {
  //   this.setState({
  //     [id]: e.target.value
  //   })
  // }

  componentDidMount() {
    // console.log(this.props)
    // this.initializeTitle(this.props.title)
    this.setState({
      [this.props.id]: this.props.editedTitle
    })
    console.log(this.state)
  }


  render() {
    // console.log(this.state)
    let { id, title, editItem, editedTitle, index } = this.props
    console.log(id)
    // console.log(index)
    // let { item } = this.state

    return (
      <div>
        <li className="list-group-item text-capitlize d-flex justify-content-between my-2">
          <h6>{title}</h6>
          <div className="todo-icon">
            <span className="mx-2 text-success" onClick={this.toggleEdit.bind(this, editItem)} >
              <i className="fas fa-pen"></i>
            </span>
            <span className="mx-2 text-danger" onClick={this.handleDelete.bind(this, id)}>
              <i className="fas fa-trash"></i>
            </span>
          </div>

          <Modal isOpen={editItem}>
            <ModalHeader>Edit Todo Item</ModalHeader>
            <ModalBody>
              <Form>
                <FormGroup row>
                  <Input type="textarea" name="text" value={this.state ? this.state[id] : ""} onChange={this.props.onChange} />
                </FormGroup>
              </Form>
            </ModalBody>
            <ModalFooter>
              <Button color="primary" onClick={this.handleEdit.bind(this, id, editedTitle)}>Save</Button>{' '}
              <Button color="secondary" onClick={this.toggleEdit.bind(this, editItem)}> Cancel</Button>
            </ModalFooter>
          </Modal>
        </li>
        {/* {editItem ? <TodoEditItem title={title} editItem={editItem} /> : ''} */}
      </div>

    )
  }
}


const mapDispatchToProps = dispatch => {
  return {
    deleteTodo: (delete_todo) => { dispatch(delete_todo) },
    editTodo: (edit_todo) => { dispatch(edit_todo) },
    toggleEdit: (toggle_edit) => { dispatch(toggle_edit) },
  }
}


export default connect(null, mapDispatchToProps)(Todoitem)

示例图片

Image of TodoItem

Image of Modal

正如您从 TodoItem 的图像中看到的那样,我正在尝试编辑“清除垃圾”,但我的文本区域已被预填充为最后一个元素。

您正在使用同一个变量来确定 TodoItem 的所有打开状态。结果是它似乎只从数组中获取最后一个值,但实际上每个模态都是同时打开的,最后一个是唯一可见的模态。

// editItem here is used to determine the open state of both modals
const { items, editItem } = this.props.todo 
...
{
  items.map((item, index) => {
    const editedTitle = item.title
    return (
      <TodoItem 
        key={item.id} 
        title={item.title}
        id={item.id}
        editedTitle={editedTitle}
        onChange={this.handleChange}
        editItem={editItem}            // Same value
      />
    )
  })
}

...

let { editItem } = this.props
<Modal isOpen={editItem}>             // All will open and close at the same time

相反,使用不同的标志,或者像这样管理每个 child 中的打开状态:

<span className="mx-2 text-success" onClick={() => this.setState({open: true})} >
  <i className="fas fa-pen"></i>
</span>

...

<Modal isOpen={this.state.open}>