我目前正在React的图像上传器组件上工作。一切正常,但是删除方法。我已经阅读了几篇有关如何更新数组/对象以及不可变状态的思想的文章。这是我尝试过的:
.filter()
.slice()
.splice()
(我怀疑这样做是否可以修改原始数组)无论尝试什么,我总是会收到此错误:
Warning: Cannot update during an existing state transition (such as within `render`). Render methods should be a pure function of props and state.
这是我的代码:
ImageUploader.js
import React, { Component } from 'react';
import styled from 'styled-components';
import FileUploadButton from '../FileUploadButton';
import ImagePreviewer from './ImagePreviewer';
import {
Typography,
Button
} from '@material-ui/core';
import theme from '../../../theme';
import uuidv5 from 'uuid/v5';
const StyledPreviewerContainer = styled.div`
display: flex;
margin: ${theme.spacing.unit}px 0;
overflow: hidden;
overflow-x: auto;
`;
export default class ImageUploader extends Component {
state = {
uploadedImages: []
}
updateImages = e => {
const { uploadedImages } = this.state,
files = [...e.target.files],
inexistentImages = files.filter(image => uploadedImages.indexOf(image) === -1);
this.setState(prevState => ({
uploadedImages: [...prevState.uploadedImages, ...inexistentImages]
}));
this.props.onChange(e);
}
removeImages = image => {
const { uploadedImages } = this.state,
imageIndex = uploadedImages.indexOf(image);
this.setState(prevState => ({
uploadedImages: prevState.uploadedImages.filter((image, index) => index !== imageIndex)
}));
};
render() {
const {
className,
label,
id,
multiple,
name,
onBlur
} = this.props, {
uploadedImages
} = this.state;
return (
<div className={className}>
<Typography>
{label}
</Typography>
<StyledPreviewerContainer>
{uploadedImages.map(image =>
<ImagePreviewer
src={URL.createObjectURL(image)}
image={image}
removeImages={this.removeImages}
key={uuidv5(image.name, uuidv5.URL)}
/>
)}
</StyledPreviewerContainer>
<FileUploadButton
id={id}
multiple={multiple}
name={name}
onChange={this.updateImages}
onBlur={onBlur}
/>
<Button>
Delete all
</Button>
</div>
);
}
}
ImagePreviewer.js
import React, { Component } from 'react';
import styled from 'styled-components';
import AnimatedImageActions from './AnimatedImageActions';
import { ClickAwayListener } from '@material-ui/core';
import theme from '../../../theme';
const StyledImagePreviewer = styled.div`
height: 128px;
position: relative;
user-select: none;
cursor: pointer;
&:not(:last-child) {
margin-right: ${theme.spacing.unit * 2}px;
}
`;
const StyledImage = styled.img`
height: 100%;
`;
export default class ImagePreviewer extends Component {
state = {
actionsOpened: false
};
openActions = () => {
this.setState({
actionsOpened: true
});
};
closeActions = () => {
this.setState({
actionsOpened: false
});
};
render() {
const {
actionsOpened
} = this.state,
{
src,
image,
removeImages
} = this.props;
return (
<ClickAwayListener onClickAway={this.closeActions}>
<StyledImagePreviewer onClick={this.openActions}>
<StyledImage src={src} />
<AnimatedImageActions
actionsOpened={actionsOpened}
image={image}
removeImages={removeImages}
/>
</StyledImagePreviewer>
</ClickAwayListener>
);
}
}
AnimatedImageActions.js
import React from 'react';
import styled from 'styled-components';
import { Button } from '@material-ui/core';
import { Delete as DeleteIcon } from '@material-ui/icons';
import { fade } from '@material-ui/core/styles/colorManipulator';
import theme from '../../../theme';
import {
Motion,
spring
} from 'react-motion';
const StyledImageActions = styled.div`
position: absolute;
top: 0;
left: 0;
color: ${theme.palette.common.white};
background-color: ${fade(theme.palette.common.black, 0.4)};
width: 100%;
height: 100%;
display: flex;
`;
const StyledImageActionsInner = styled.div`
margin: auto;
`;
const StyledDeleteIcon = styled(DeleteIcon)`
margin-right: ${theme.spacing.unit}px;
`;
const AnimatedImageActions = ({ actionsOpened, removeImages, image }) =>
<Motion
defaultStyle={{
scale: 0
}}
style={{
scale: spring(actionsOpened ? 1 : 0, {
stiffness: 250
})
}}
>
{({ scale }) =>
<StyledImageActions style={{
transform: `scale(${scale})`
}}>
<StyledImageActionsInner>
<Button
color="inherit"
onClick={removeImages(image)}
>
<StyledDeleteIcon />
Delete
</Button>
</StyledImageActionsInner>
</StyledImageActions>
}
</Motion>
;
export default AnimatedImageActions
任何帮助将不胜感激!
答案 0 :(得分:3)
是onClick={removeImages(image)}
应该是onClick={()=>removeImages(image)}
吗?
否则,removeImages
在setState
的渲染过程中调用AnimatedImageActions
。