如何在componentDidUpdate方法中更新数组对象

时间:2019-06-08 04:16:24

标签: reactjs

我正在尝试在componentDidUpdate方法中获取新的更新状态对象。但它会返回数组中的旧值。

用户输入图像标题,然后上传图像,并应使用新值console.log新建一个数组对象。无需刷新。

例如,考虑到我只是添加了一个图像而未刷新,以下数组应该具有两个键以及数组中的值。

enter image description here

并在刷新后更新阵列

enter image description here

  

dashboard.js 66

这是console.log(prevState.images)

[
  {
    "id": 139,
    "image_title": "owl",
    "img_url": "http://res.cloudinary.com/dq281hpqd/image/upload/v1559966278/uploads/wph0kuhzg52lxkhxmxsi.png",
    "created_at": "2019-06-08T03:57:58.351Z",
    "updated_at": "2019-06-08T03:57:58.351Z",
    "user_id": null
  },
  {
    "id": 138,
    "image_title": "uuuuuu",
    "img_url": "http://res.cloudinary.com/dq281hpqd/image/upload/v1559965905/uploads/m1oxtyae2d6pyvteidyq.png",
    "created_at": "2019-06-08T03:51:46.815Z",
    "updated_at": "2019-06-08T03:51:46.815Z",
    "user_id": null
  }
]

理想情况下,具有新值的新对象数组应在不刷新页面的情况下追加数组。

Dashboard.js

import React, { Component } from "react";
import Button from '@material-ui/core/Button';
import TextField from '@material-ui/core/TextField';
import Grid from '@material-ui/core/Grid';
import Typography from '@material-ui/core/Typography';
import Paper from '@material-ui/core/Paper';
import ImageUploader from 'react-images-upload';
import Axios from '../Axios';
import Image from './Image';
class Dashboard extends Component{
    constructor(props){
        super(props);
        this.state = {
            image_url: 'http://www.conservewildlifenj.org/images/artmax_1001.jpg', 
            images: [], 
            description:'',
            upload:false,
        }
    }
    handleUpload =  file =>  {
        const data = new FormData()
        const image = file[0]
        // console.log(this.state.description)
        // data.append('ourImage', this.state.description)
        data.append('ourImage',image, this.state.description )
        Axios.post('/images/upload', data).then((response) => {
            this.setState({
                image_url:response.data.img_url,
                description:response.data.image_title
                // images: [...this.state.images, this.state.image_url ]
            })
        });
        this.props.history.push("/dashboard");
    }
    handleChange = (e) => {
        // e.preventDefault();
        this.setState({
            [e.target.name]: e.target.value
        })
        // console.log(this.state.description)
    }
    fileOnchange = (file) => {
        this.setState({
            [file[0].target.name]: file[0].target.value
        })
    }
    componentWillMount(){
        Axios.get('/images/uploads').then( (response) => {
            // let img;
            // let imgTitle;
            Object.keys(response.data).forEach( (key) => {
                // console.log(response.data);
                // img = response.data[key].img_url
                // imgTitle = response.data[key].image_title
                // pulling in the data from the backend
                console.log(response.data[key]);
                this.setState({
                    images:[ ...this.state.images, response.data[key]]
                })
                console.log(this.state.images);
            });
        })
    }
    componentDidUpdate(prevProps, prevState) {
        if (this.state.image_url !== prevState.image_url) {
            // trying to fetch the new upated array. but not sure how. 
            console.log(prevState.images);
            this.setState({
                images: [this.state.image_url, this.state.description, ...this.state.images]
            });
        }
      }
    onUploadClick = (e) => {
        e.preventDefault();
        this.setState({
            upload: !this.state.upload
        })
    }
    render(){
        const uploader = ( 
            <ImageUploader
                withIcon={true}
                withPreview={true}
                onChange={this.handleUpload}
                singleImage={true}
                buttonText='Upload an image'
                imgExtension={['.jpg', '.gif', '.png', '.gif']}
                maxFileSize={5242880}
            />
        )
        return(
            <div>
            <Grid container justify="center" spacing={16}>
                <Grid item sm={8} md={6} style={{ margin: '40px 0px', padding: '0px 30px'}}>
                    <Typography align="center" variant="h6">
                        Welcome to the Dashboard
                    </Typography>
                        <Button onClick={this.onUploadClick} variant="outlined" component="span" color="primary">
                            {/* toggle between Upload or Close
                                Will be upload by default, else if upload is clicked, close will show.
                            */}
                            {!this.state.upload ? "Upload": "Close"}
                        </Button>
                        {this.state.upload ? (
                            <div>
                             <TextField
                                 id="outlined-name"
                                 label="Image Title"
                                 name="description"
                                 type="text"
                                 fullWidth
                                 style={{ borderRadius: '0px'}}
                                 className=""
                                 value={this.state.description}
                                 onChange={this.handleChange}
                                 margin="normal"
                               />
                                <br></br>
                                <br></br>
                              {uploader}
                            </div>
                        ):(
                            null
                        )}
                    {this.state.images.length > 0 ? (
                        this.state.images.map( (img, i) => (     
                            <Grid item sm={12} md={12} key={i} style={{ margin: '30px 0px'}}>
                                 <Paper>
                                        {/* // empty image_title */}
                                     <Typography variant="h6" align="center">{img.image_title}</Typography> 
                                    <Image image_url={img.img_url} />    
                                </Paper>                              
                            </Grid>
                        ))
                    ) : (
                        <div>
                            <Grid item md={8}>
                                <Typography>No Images yet</Typography>
                            </Grid>
                        </div>
                    )}
                </Grid>
                {/* Images  */}
              </Grid>
            </div>
        )
    }
}
export default Dashboard;

componentDidUpdate

console.log(this.state.images);

传递值,但不是我想要的方式

enter image description here

最后两个值不在嵌套数组中。和其他人一样。

[
  {
    "id": 142,
    "image_title": "cheese",
    "img_url": "http://res.cloudinary.com/dq281hpqd/image/upload/v1559973164/uploads/bvfotlfivr4yqsqhkvrw.png",
    "created_at": "2019-06-08T05:52:45.203Z",
    "updated_at": "2019-06-08T05:52:45.203Z",
    "user_id": null
  },
  {
    "id": 141,
    "image_title": "owl",
    "img_url": "http://res.cloudinary.com/dq281hpqd/image/upload/v1559972965/uploads/w9aup9r76q6hiktdjvyp.png",
    "created_at": "2019-06-08T05:49:26.911Z",
    "updated_at": "2019-06-08T05:49:26.911Z",
    "user_id": null
  },
  {
    "id": 140,
    "image_title": "tea",
    "img_url": "http://res.cloudinary.com/dq281hpqd/image/upload/v1559966806/uploads/y9q4upguo3hy6vhkk0va.png",
    "created_at": "2019-06-08T04:06:47.217Z",
    "updated_at": "2019-06-08T04:06:47.217Z",
    "user_id": null
  },
  {
    "id": 139,
    "image_title": "owl",
    "img_url": "http://res.cloudinary.com/dq281hpqd/image/upload/v1559966278/uploads/wph0kuhzg52lxkhxmxsi.png",
    "created_at": "2019-06-08T03:57:58.351Z",
    "updated_at": "2019-06-08T03:57:58.351Z",
    "user_id": null
  },
  {
    "id": 138,
    "image_title": "uuuuuu",
    "img_url": "http://res.cloudinary.com/dq281hpqd/image/upload/v1559965905/uploads/m1oxtyae2d6pyvteidyq.png",
    "created_at": "2019-06-08T03:51:46.815Z",
    "updated_at": "2019-06-08T03:51:46.815Z",
    "user_id": null
  },
  "http://www.conservewildlifenj.org/images/artmax_1001.jpg",
  "cheese2"
]

1 个答案:

答案 0 :(得分:1)

当您执行handleUpload()时,似乎只是没有将新的图像对象正确地传递到组件状态,我将其分解为以下部分:

这很好:

handleUpload =  file =>  {
    const data = new FormData()
    const image = file[0]
    data.append('ourImage',image, this.state.description )
    Axios.post('/images/upload', data).then((response) => {

创建新图像的浅表副本:

这是一个好习惯,因此您不会意外地更改原始对象。 虽然说实话,我们可能不需要这样做,因为该项目存储在您的数据库中,并且此处的任何突变都不会影响它

    const newImage = {...response.data}

我们想要一个包含旧对象的所有键值对的新对象。由于图像对象仅具有一层数据{ key: string }而不是{ key: {} }的一层数据,因此使用扩展运算符...就足够了。

之所以这样做,是因为我们永远不想遇到这样的情况:

const newImage = response.data // { url: "https://boygeniusreport.files.wordpress.com/2015/06/funny-cat.jpg?quality=98&strip=all&w=782"}

newImage.url = "https://boygeniusreport.files.wordpress.com/2016/05/scared-surprised-cat-face.jpg?quality=98&strip=all&w=782"

我们的期望是我们的代码只会更改newImage中的url,但我们发现response.data也已更改:

console.log(newImage.url) //"https://boygeniusreport.files.wordpress.com/2016/05/scared-surprised-cat-face.jpg?quality=98&strip=all&w=782"
console.log(response.data.url)  //"https://boygeniusreport.files.wordpress.com/2016/05/scared-surprised-cat-face.jpg?quality=98&strip=all&w=782"

在JavaScript中,当您复制对象const newImage = oldImage时,您不仅可以复制其值。您将其整个参考复制到内存中。使用...进行浅表复制可以通过创建全新的引用来解决此问题。如果您想在最初复制的对象内定义新值,则最好创建一个浅表复制

更新组件状态

        this.setState({
            image_url: newImage.img_url,
            description: newImage.image_title,
            images: [
               ...this.state.images,
               {
                  id: newImage.id,
                  image_title: newImage.image_title,
                  img_url: newImage.img_url,
                  created_at: newImage.created_at,
                  updated_at: newImage.updated_at,
                  user_id: null
               }
            ]
        })

    });
}

此处的代码块表示,我们将制作this.state.images的浅表副本,然后使用newImage obj中的值创建一个新对象。您还记得,newImage是通过创建response.data的浅表副本而制成的。因此,newImage具有我们所需的所有键值对。

images: [
   ...this.state.images,
   {
      id: newImage.id,
      image_title: newImage.image_title,
      img_url: newImage.img_url,
      created_at: newImage.created_at,
      updated_at: newImage.updated_at,
      user_id: null
   }
]

此外,当您调用componentDidUpdate()时,您仅将说明 image_url 作为单独的值添加到images数组。这似乎是一个错误,您已经在handleClick()中添加了图像。但是,如果真的想要汤姆,那么您应该传入一个类似的对象。

componentDidUpdate(prevProps, prevState){
    if(this.state.images.length !== prevState.images.length){
       //unnecessary, since we already added the image, but test it out anyway.
       this.setState({
           images: [...this.state.images, { image_url: this.state.image_url, description: this.state.description}]
       })
    }
} 

注意:如果您决定使用componentDidUpdate(),将注意到您将没有"created_at", "updated_at"等可用字段,因为这些字段是从后端API添加到新图像对象的字段。 / p>