ReactJS:组件数组问题

时间:2019-05-10 02:10:58

标签: javascript arrays reactjs

我有一个Main.js页面,其中有一个按钮:单击它时,它将向数组和页面添加一个Block组件。您可以根据需要添加任意数量的块组件。每个“块”组件都有一个“删除”按钮,该按钮将从阵列和页面中删除该块。

Menu.js:

import React from 'react';
import './Menu.css';
import Block from './Block.js';
import './Block.css';

export default class Menu extends React.Component {

  constructor(props) {

    super(props);

    this.state = { value: '', blocksArray: [] };

    this.addBlock = this.addBlock.bind(this);
    this.removeBlock = this.removeBlock.bind(this);

    this.blocks = [];

  }

  addBlock() {

    this.blocks.push({ title: 'Section title' + this.blocks.length, content: 'Content' + this.blocks.length });
    this.setState({ value: '', blocksArray: this.blocks });
  }

  removeBlock(index) {
    this.blocks.splice(index, 1);
    this.setState({ value: '', blocksArray: this.blocks })
  }

  renderBlocks = () => {
    return (
      this.state.blocksArray.map((block, index) =>
      <Block
        remove={() => this.removeBlock(index)} 
        key={index}
        title={block.title}
        content={block.content}
      />  
      )
    )
  }

  render() {
    return (
      <div>
        <div className="Menu">
          <header className="Menu-header">
            <button className="Menu-button" onClick={ () => this.addBlock() }>Add block</button>
          </header>
        </div>
        <div>
          { this.renderBlocks() }
        </div>
      </div>
    );
  }
}

Block.js(版本1)

import React from 'react';
import './Block.css';

class Block extends React.Component {
    constructor(props) {

        super(props);

        this.state = {
            title: props.title,
            content: props.content,
            remove: props.remove
        };

        this.handleChange = this.handleChange.bind(this);
        this.handleSubmit = this.handleSubmit.bind(this);
    }

    handleChange(event) {
        this.setState({[event.target.name]: event.target.value});
    }

    handleSubmit(event) {
        //alert('A name was submitted: ' + this.state.title);
        event.preventDefault();
    }

    render() {
      return (
        <div className="Block-container">
            <form onSubmit={this.handleSubmit}>
                <div className="Block-title">
                    <label>
                        Title: 
                        <input type="text" name="title" value={this.props.title} onChange={this.handleChange} />
                    </label>
                </div>
                <div className="Block-content">
                    <label>
                        Content: 
                        <input type="text" name="content" value={this.props.content} onChange={this.handleChange} />
                    </label>
                </div>
                <input type="submit" value="Save"  />
                <input type="button" value="Delete" onClick= { () => this.state.remove() } />
            </form>
        </div>
      );
    }
  }

export default Block;

问题:我发现自己陷入了两种情况,但都无法正常工作。

第一个Block.js无效解决方案:

<input type="text" name="title" value={this.props.title} onChange={this.handleChange} />

<input type="text" name="content" value={this.props.content} onChange={this.handleChange} />

如果我在块上按下删除按钮时使用value = {this.props.content}和value = {this.props.title},它可以工作,但是我无法在该字段中编辑文本因为它的值始终是从道具中获取的

Block.js的第二个无效解决方案:

<input type="text" name="title" value={this.state.title} onChange={this.handleChange} />

<input type="text" name="content" value={this.state.content} onChange={this.handleChange} />

如果我使用value = {this.state.content}和value = {this.state.title},我可以编辑文本字段,当我按下Block上的Delete按钮时,它会从数组中正确删除组件, 在字段中显示的文本是错误的(好像总是只弹出数组中的最后一个组件一样)。让我用一些屏幕截图进行解释。

假设我添加了4个Block组件,如下所示:

enter image description here

然后,单击带有“ Section title1” /“ Content1”的块的删除按钮,如下图所示:

enter image description here

它显然删除了数组中的正确元素,但是由于某种原因,我在组件中得到了错误的文本:

阵列console.log:

0: Object { title: "Section title0", content: "Content0" }
1: Object { title: "Section title2", content: "Content2" }
2: Object { title: "Section title3", content: "Content3" }

显示的文字:

enter image description here

我显然错过了一些东西,并且被困了一段时间。有人可以解释出什么问题吗?

2 个答案:

答案 0 :(得分:2)

我认为问题在于您正在将index设置为每个Block的键。 原始键为[0,1,2,3]。当您删除Section title1时,新的渲染将产生关键帧[0,1,2]。因此,React假定键[0、1、2]的元素未更改,而键3被删除。因此,它删除了最后一个。 尝试对键使用唯一的属性。 您可以在此处了解更多信息:https://reactjs.org/docs/reconciliation.html#keys

答案 1 :(得分:1)

您的更改处理程序需要在标题/内容来自的父组件中的状态下运行。块中显示的值是从菜单的状态读取的,因此在编辑块数据时会更改其自身的内部状态,因为道具内部的状态不会被反馈,所以从菜单到块的值保持不变

您可以在菜单状态下编写一个函数来编辑数组:

this.editBlock = this.editBlock.bind(this);

...

  editBlock(index, newBlock) {
    let blocks = Array.from(this.state.blocksArray);
    blocks[index] = newBlock;
    this.setState({
      blocksArray: blocks
    })
  }

然后将其作为道具传递给Block并在change事件触发时调用它:

      <Block
        remove={() => this.removeBlock(index)} 
        key={index}
        title={block.title}
        content={block.content}
        index={index}
        editBlock={this.editBlock}
      />  
    handleChange(event) {
        this.setState({[event.target.name]: event.target.value}, () => {
          this.props.editBlock(this.props.index, { title: this.state.title, content: this.state.content})
        });
    }

正在运行的演示here