如何管理子组件状态数组?

时间:2019-03-07 15:28:26

标签: reactjs firebase react-native firebase-storage

我是新来的反应者,所以请原谅我。我在理解状态(尤其是儿童状态)时遇到问题。

目的:我正在尝试创建一种表单,用户可以添加越来越多的组件(在这种情况下为图像)。

会发生什么:用户附加了2张或更多图片。用户尝试上传带有UploadButton组件的图像,但是两个图像是相同的。我相信这与两个共享相同状态的附加孩子有关。

问题:如何在不影响其他附加孩子的情况下为每个附加孩子提供自己的图像?

class Page extends Component
  constructor (props) {
    super(props);

    this.state = { 
      id: '', 
      numChildren: 0,
      images: [],
    }
    this.onAddChild = this.onAddChild.bind(this);
  }

  showModal() {
    this.setState({
      numChildren: 0,
      images: [],
    });
  }

  renderModal() 
    const children = [];
    //Here's my array of child components
    for(var i = 0; i < this.state.numChildren; i += 1) {
        children.push(<this.ChildComponent key={i} />);
    }

    return (
      <ReactModal>
        <this.ParentComponent addChild={this.onAddChild}>
          {children}
        </this.ParentComponent>
      </ReactModal>
    )
  }

  onAddChild = () => {
    this.setState({
      numChildren: this.state.numChildren + 1
    })
  }

  ParentComponent = (props) => (
    <div>
      {props.children}
      <Button onClick={props.addChild}>Add Item</Button>
    </div>
  );

  ChildComponent = () => (
    <div>
      <UploadButton
        storage="menus"
        value={this.state.images}
        onUploadComplete={uri => this.setState({images: uri})}
      />
    </div>
  );
}

这是UploadButton的代码:

import React, { Component } from 'react';
import uuid from 'uuid';
import firebase from '../config/firebase';

class UploadButton extends Component {

  constructor(props) {
    super(props);

    this.state = {
      isUploading: false
    }
  }

  handleClick() {
    const input = document.createElement("INPUT");
    input.setAttribute("type", "file");
    input.setAttribute("accept", "image/gif, image/jpeg, image/png");
    input.addEventListener("change", ({target: {files: [file]}}) => this.uploadFile(file));
    input.click();
  }

  uploadFile(file) {
    console.log('F', file);
    const id = uuid.v4();
    this.setState({ isUploading: true })
    const metadata = {
      contentType: file.type
    };
    firebase.storage()
      .ref('friends')
      .child(id)
      .put(file, metadata)
      .then(({ downloadURL }) => {
        this.setState({ isUploading: false })
        console.log('Uploaded', downloadURL);
        this.props.onUploadComplete(downloadURL);
      })
      .catch(e => this.setState({ isUploading: false }));

  }

  render() {
    const { 
      props: {
        value,
        style = {},
        className = "image-upload-button",
      },
      state: {
        isUploading    
      }
    } = this;

    return (
      <div 
        onClick={() => this.handleClick()}
        className={className}
        style={{
          ...style,
          backgroundImage: `url("${this.props.value}")`,          
        }}>
        {isUploading ? "UPLOADING..." : !value ? 'No image' : ''}
      </div>
    );
  }

}


export default UploadButton;

我试图排除所有与我的问题无关的不必要的代码,但是请告诉我是否需要显示更多内容。

编辑:这是我的尝试,不起作用:

//altered my children array to include a new prop
renderModal() {
  const children = [];
  for (var i = 0; i < this.state.numChildren; i += 1) {
    children.push(<this.ChildComponent imageSelect={this.onImageSelect} key={i} />);
  }
  //...
};

//my attempt to assign value and pass selected image back to images array
ChildComponent = () => (
  <div>
    <UploadButton
        storage="menus"
        value={uri => this.props.onImageSelect(uri)} //my greenness is really apparent here
        onUploadComplete={uri => this.setState({images: uri})}
    /> 
    //...
  </div>
);

//added this function to the class
onImageSelect(uri) {
  var el = this.state.images.concat(uri);
  this.setState({
    images: el
  })
}

我知道我没有正确访问子道具。这是我到目前为止所处理的最复杂的事情。感谢您的宝贵时间。

1 个答案:

答案 0 :(得分:0)

在“子级/父级”组件中写入this.state时,实际上是在访问Page的状态。现在,我建议您像这样将孩子的索引传递给孩子。

children.push(<this.ChildComponent key={i} index={i}/>)

这样每个孩子只能像这样处理自己的图像

ChildComponent = ({index}) => (
    <div>
      <UploadButton
        storage="menus"
        value={this.state.images[index]}
        onUploadComplete={uri => {
          let images = this.state.images.slice()
          images[index] = uri
          this.setState({images})
        }}
      />
    </div>
  );