reactjs - react 在状态更改时不获取api属性,而是在重新渲染时获取?
问题描述
我收到此错误
img.user.username 未定义。
<Typography variant="h6" align="center">{img.user.username}</Typography>
上传图片时
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) => {
const newImage = {...response.data}
//update component-state
this.setState({
image_url: newImage.img_url,
description: '',
images: [
{
id: newImage.id,
// user: newImage.user.username,
image_title: newImage.image_title,
img_url: newImage.img_url,
created_at: new Date().toLocaleString().replace(',', ''),
updated_at: new Date().toLocaleString().replace(',', '')
},
...this.state.images,
],
})
});
}
{...response.data}
不包含该属性user
,因此此错误是可以理解的,但是当我刷新页面时
img.user.username
显示用户名。他们没有错误。
这从后端获取帖子,我怎样才能让它双向工作,比如上传图像时以及刷新页面时。
如果他们是编辑问题标题的更好方法,请制作更好的问题标题。
componentWillMount(){
Axios.get('/images/uploads').then( (response) => {
// let img;
// let imgTitle;
Object.keys(response.data).forEach( (key) => {
console.log(response.data[key]);
this.setState({
images:[ ...this.state.images, response.data[key]]
})
console.log(this.state.images);
});
})
}
完整代码
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 Divider from '@material-ui/core/Divider';
import Axios from '../Axios';
import Image from './Image';
import moment from 'moment';
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) => {
const newImage = {...response.data}
//update component-state
this.setState({
image_url: newImage.img_url,
description: '',
images: [
{
id: newImage.id,
// user: newImage.user.username,
image_title: newImage.image_title,
img_url: newImage.img_url,
created_at: new Date().toLocaleString().replace(',', ''),
updated_at: new Date().toLocaleString().replace(',', '')
},
...this.state.images,
],
})
});
}
handleChange = (e) => {
// e.preventDefault();
this.setState({
[e.target.name]: e.target.value
})
// console.log(this.state.description)
}
componentWillMount(){
Axios.get('/images/uploads').then( (response) => {
// let img;
// let imgTitle;
Object.keys(response.data).forEach( (key) => {
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.images.length !== prevState.images.length) {
console.log(this.state.images);
}
// debugger;
}
onUploadClick = (e) => {
e.preventDefault();
this.setState({
upload: !this.state.upload
})
}
deleteImg = (id) => {
Axios.post(`/images/delete/${id}`).then( () => {
this.setState({
images: [ ...this.state.images.filter(img => img.id !== id)]
})
})
}
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>
<br></br>
<br></br>
{this.state.upload ? (
<div>
<TextField
id="outlined-name"
label="Image Title"
name="description"
type="text"
required={true}
fullWidth
style={{ borderRadius: '0px'}}
className=""
value={this.state.description}
onChange={this.handleChange}
margin="normal"
/>
<br></br>
<br></br>
{/* so here what we are saying, if this text field is FILLED show the uploader component
else hide it.
*/}
{this.state.description ? uploader : null}
</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 style={{padding:'20px 20px'}}>
{/* // empty image_title */}
<Typography style={{ padding: '30px 5px', letterSpacing:'8px', textTransform:'uppercase'}} variant="h4" align="center">{img.image_title}</Typography>
<Divider style={{ width: '150px', margin:'10px auto', backgroundColor:'#000000'}} variant="middle" />
<Image image_url={img.img_url} />
<Typography variant="h6" align="center">{img.user.username}</Typography>
<Typography variant="h6" align="center">{moment(img.created_at).calendar()}</Typography>
<Button onClick={() => this.deleteImg(img.id)} variant="outlined" component="span" color="primary">
Delete
</Button>
</Paper>
</Grid>
))
) : (
<div>
<Grid item md={8}>
<Typography>No Images yet</Typography>
</Grid>
</div>
)}
</Grid>
{/* Images */}
</Grid>
</div>
)
}
}
export default Dashboard;
后端
router.get('/uploads', async (req, res) => {
await Image.query( (image) => {
image.orderBy('img_url', 'DESC')
image.limit(10)
// if you want to include the user with the image, you would use the withRelated
}).fetchAll({withRelated: ['user']}).then( (images) => {
// console.log(images.toJSON());
return res.status(200).json(images.toJSON());
})
})
router.post('/upload', multipartMiddleware, upload.single('ourImage'), (req, res) => {
if(!req.files){
return res.status(500).send("Please upload a file");
}
// console.log(req.files)
cloud.uploader.upload(req.files.ourImage.path, {crop: "fill", folder: '/uploads'} , (err, result) => {
if(err){
return res.status(500).send(err);
}
// console.log(req.user)
const img = new Image({
img_url:result.url,
image_title:req.files.ourImage.name,
user_id: req.user.id
});
// console.log(img);
img.save().then( img => {
return res.status(200).json(img);
});
});
});
解决方案
首先,确保后端 POST 响应以与 GET 响应相同的格式返回您的数据。
const img = new Image({
img_url:result.url,
image_title:req.files.ourImage.name,
user_id: req.user.id
});
Image.save().then(img => {
/* Do something like this, but for a single image...
await Image.query(image => {
image.orderBy("img_url", "DESC");
image.limit(10);
})
.fetchAll({ withRelated: ["user"] })
.then(images => {
return res.status(200).json(images);
});
*/
});
此外,当您在 handleUpload 方法中调用 setState 时,您不会user.username
在要附加到图像数组的新对象上设置属性。也许尝试更换
this.setState({
images: [
{
id: newImage.id,
// user: newImage.user.username,
image_title: newImage.image_title,
img_url: newImage.img_url,
created_at: new Date().toLocaleString().replace(',', ''),
updated_at: new Date().toLocaleString().replace(',', '')
},
...this.state.images
]
})
和
this.setState({
images: [
{
id: newImage.id,
user: {
username: newImage.user.username
},
image_title: newImage.image_title,
img_url: newImage.img_url,
created_at: new Date().toLocaleString().replace(',', ''),
updated_at: new Date().toLocaleString().replace(',', '')
},
...this.state.images
]
})
或进一步简化
this.setState(prevState => ({
images: [
{
...newImage,
created_at: new Date().toLocaleString().replace(',', ''),
updated_at: new Date().toLocaleString().replace(',', '')
},
...prevState.images
]
}))
推荐阅读
- cmake - 如何在 Windows 中使用 cmake 构建和链接谷歌基准测试
- d3.js - 我可以在 d3.js 轴中定义最大刻度数吗?
- python - 在 Python 中手动输入中位数作为 K-means 的质心
- django - 如何在 Django 模型中返回数组字段?
- javascript - 在嵌入 HTML 的 Shiny 应用程序中包含 AmChart
- javascript - 如何将状态元素推送到状态数组?
- jquery - 如何在 laravel ajax 中更改针对 id 的状态?
- android - Gradle 构建失败 ....Failed to create component for 'dialog' 原因:java.awt.HeadlessException
- sql - Case When 语句的意外结果
- javascript - 如何在 setInterval(function(){...}) 中传递服务器发送事件对象