React modal 总是取 map 函数的最后一个元素 [英] React modal always take the last element of map function

查看:60
本文介绍了React modal 总是取 map 函数的最后一个元素的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在创建一个 React 待办事项应用程序.所以基本上我有两个组件 TodoList 和 TodoItem

TodoList 组件将接收一个包含 title 作为属性的对象数组,并通过 TodoItem 组件映射此数组

在我的 TodoItem 组件中,用户可以选择编辑或删除项目.如果用户选择编辑,则会使用文本区域显示带有现有标题的模式.但是,我在实现这个函数时遇到了麻烦,因为模态总是与数组的最后一个元素一起显示.

TodoList 组件

import React, { Component } from 'react'从 './TodoItem' 导入 TodoItem从'react-redux'导入{连接}从 '../store/actions/todoActions' 导入 { clear_todo }类 Todolist 扩展组件 {clearList = (e) =>{e.preventDefault()this.props.clearList(clear_todo());}handleChange = (index, title) =>{this.setState({[索引]:标题})}使成为() {const { items, editItem } = this.props.todo返回 (<ul className="list-group my-5"><h3 className="text-capitalize text-center">待办事项列表{items.map((item, index) => {consteditedTitle = item.titlereturn (<TodoItem key={item.id} title={item.title}id={item.id}编辑标题={编辑标题}onChange={this.handleChange}editItem={editItem}/>)})}<button className="btn btn-danger btn-block text-capitalize mt-5";onClick={this.clearList}>清除列表</button>)}}const mapStateToProps = state =>{返回 {待办事项:state.todo}}const mapDispatchToProps = dispatch =>{返回 {clearList: (clear_todo) =>{调度(clear_todo)}}}导出默认连接(mapStateToProps,mapDispatchToProps)(Todolist)

TodoItem 组件

import React, { Component } from 'react'从'react-redux'导入{连接}从'../store/actions/todoActions'导入{delete_todo,edit_todo,toggle_edit}import { Button, Modal, ModalHeader, ModalBody, ModalFooter, Form, FormGroup, Input } from 'reactstrap';从 './TodoEditItem' 导入 TodoEditItem类 Todoitem 扩展组件 {//构造函数(道具){//超级(道具)//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)让 { id, title, editItem,editedTitle, index } = this.props控制台日志(ID)//控制台日志(索引)//让 { item } = this.state返回 (<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>

<Modal isOpen={editItem}><ModalHeader>编辑待办事项</ModalHeader><模态体><表格><表单组行><输入类型=文本区域"名称=文本"值={this.state ?this.state[id] : ""} onChange={this.props.onChange}/></FormGroup></表格></ModalBody><模态页脚><按钮颜色=主要"onClick={this.handleEdit.bind(this, id,editedTitle)}>Save</Button>{' '}<按钮颜色=次要";onClick={this.toggleEdit.bind(this, editItem)}>取消</ModalFooter></模态>{/* {编辑项目?<TodoEditItem title={title} editItem={editItem}/>: ''} */}

)}}const mapDispatchToProps = dispatch =>{返回 {deleteTodo: (delete_todo) =>{调度(delete_todo)},editTodo: (edit_todo) =>{调度(edit_todo)},切换(toggle_edit)=>{调度(toggle_edit)},}}导出默认连接(null,mapDispatchToProps)(Todoitem)

示例图片

TodoItem 的图片

Modal 图像

从 TodoItem 的图片中可以看出,我正在尝试编辑取出垃圾"但我的 textarea 已预先填充为最后一个元素.

解决方案

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

//这里的editItem用于判断两个modals的打开状态const { items, editItem } = this.props.todo...{items.map((item, index) => {consteditedTitle = item.title返回 (<待办事项键={item.id}标题={item.title}id={item.id}编辑标题={编辑标题}onChange={this.handleChange}editItem={editItem}//相同的值/>)})}...让 { editItem } = this.props<Modal isOpen={editItem}>//所有将同时打开和关闭

相反,使用不同的标志,或者像这样管理每个孩子的开放状态:

this.setState({open: true})} ><i className="fas fa-pen"></i></span>...<Modal isOpen={this.state.open}>

I am currently creating a React todo application. So basically I have two component TodoList and TodoItem

TodoList component will receive an array of objects consisting title as the property and map through this with TodoItem component

In my TodoItem component, the user can choose to edit or delete the item. If the user chose to edit, a modal will show up with the existing title using a textarea. However, I have trouble implementing this function as the modal will always show up with the last element of the array.

TodoList Component

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 Component

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)

Sample Image

Image of TodoItem

Image of Modal

As you can see from the image of TodoItem, I am trying to edit "Take out the garbage" but my textarea has been prepopulated as the last element.

解决方案

You're using the same variable to determine all of the TodoItem's open state. The result is it appears that it is only taking the last value from the array, but really each modal is opening at once and the last one is the only visible modal.

// 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

Instead, use a different flag, or just manage the open state in each child like this:

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

...

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

这篇关于React modal 总是取 map 函数的最后一个元素的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
其他开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆