#javascript #reactjs #redux #redux-form
Вопрос:
У меня есть список пользователей, отображаемых на странице при разбиении на страницы. Каждый профиль пользователя можно изменить, нажав кнопку Изменить. В модале есть опция выбора и загрузки изображения, а затем обрезки. Выбор изображения , обрезка и загрузка работают нормально, но проблема в том, что если я выберу изображение, затем закрою модальное, а затем перейду к следующему пользователю, он покажет то же изображение для обрезки без нажатия кнопки выбора. Вторая проблема связана с первой, после загрузки изображения. при выборе любого пользователя для редактирования отображается та же картинка.
Страница: UserUpdateModal.js:
<AccountProfileForm
submitCb={this.updateProfile}
errors={errors}
options={this.options}
initialValues ={this.props.initialValues}
randomId={this.randomId()}
/>
Страница AccountProfileForm.js
<Field
name="first_name"
type="text"
label='First Name'
className='form-control'
component={BwmInput}
validate={[required,text,minLength2, maxLength32]}
/>
<Field
name="image_link"
id={id}
type="file"
label='Image'
className='form-control'
component={BwmFileUpload}
/>
Вот основной класс для загрузки:
BwmFileUpload.js
import React from 'react';
import ReactCrop, { makeAspectCrop } from 'react-image-crop';
import { toast } from 'react-toastify';
import * as actions from '../../../actions';
import { v4 as uuidv4 } from 'uuid';
export class BwmFileUpload extends React.Component {
constructor() {
super();
this.state = {
src: null,
selectedFile: undefined,
imageBase64: '',
initialImageBase64: '',
croppedImageUrl: {},
blob:{},
pending: false,
status: 'INIT',
crop: {
unit: '%',
width: 50,
aspect: 3 / 4,
}
}
}
imageId=() =>{
let id = Math.floor(Math.random() * 100) 1;
return id;
}
resetToDefaultState(status) {
this.setState({
pending: false,
status,
selectedFile: undefined,
croppedImage: {},
crop: {},
initialImageBase64: '',
imageBase64: ''
});
}
onSelectFile = e => {
const selectedFile = e.target.files[0];
if (e.target.files amp;amp; e.target.files.length > 0) {
const reader = new FileReader();
reader.addEventListener('load', () =>
this.setState({ src: reader.result,selectedFile })
);
reader.readAsDataURL(selectedFile);
}
};
onCropChange=(crop) =>{
this.setState({ crop });
}
onImageLoaded = image => {
this.imageRef = image;
if (image.naturalWidth > 1920 amp;amp; image.naturalHeight > 1080) {
this.resetToDefaultState('INIT');
toast.error('Max width of an image is 1920px and height 1080px');
return;
}
}
onCropComplete = crop => {
this.makeClientCrop(crop);
};
async makeClientCrop(crop) {
const { selectedFile } = this.state;
if (this.imageRef amp;amp; crop.width amp;amp; crop.height) {
const croppedImageUrl = await this.getCroppedImg(this.imageRef, crop, selectedFile.name);
this.setState({ croppedImageUrl });
}
}
getCroppedImg(image, crop, fileName) {
const canvas = document.createElement('canvas');
const scaleX = image.naturalWidth / image.width;
const scaleY = image.naturalHeight / image.height;
canvas.width = crop.width;
canvas.height = crop.height;
const ctx = canvas.getContext('2d');
ctx.drawImage(
image,
crop.x * scaleX,
crop.y * scaleY,
crop.width * scaleX,
crop.height * scaleY,
0,
0,
crop.width,
crop.height
);
return new Promise((resolve, reject) => {
canvas.toBlob(blob => {
if (!blob) {
//reject(new Error('Canvas is empty'));
toast.error('Canvas is empty');
return;
}
blob.name = fileName;
this.setState({blob});
window.URL.revokeObjectURL(this.fileUrl);
this.fileUrl = window.URL.createObjectURL(blob);
resolve(this.fileUrl);
}, 'image/jpeg');
});
}
onError=(error)=> {
this.setState({pending: false, status: 'FAIL'});
}
onSuccess = (uploadedImage) => {
const {onChange} = this.props.input || this.props;
this.resetToDefaultState('INIT');
onChange(uploadedImage);
this.setState({src: null,selectedFile:undefined});
}
uploadImage=()=> {
const { blob } = this.state;
if (blob) {
this.setState({pending: true, status: 'INIT'});
actions.uploadImage(blob, 'users').then(
(uploadedImage) => { this.onSuccess(uploadedImage) },
(error) => { this.onError(error)})
}
}
renderSpinningCircle() {
const { pending } = this.state;
if (pending) {
return (
<div className='img-loading-overlay'>
<div className='img-spinning-circle'>
</div>
</div>
)
}
}
renderImageStatus() {
const { status } = this.state;
if (status === 'OK') {
return <div className='alert alert-success'> Image Uploaded Succesfuly! </div>
}
if (status === 'FAIL') {
return <div className='alert alert-danger'> Image Upload Failed! </div>
}
}
render() {
const {crop,croppedImageUrl, src } = this.state;
return (
<div className='img-upload-container' id={this.imageId()}>
<label className='img-upload btn btn-bwm'>
<span className='upload-text'> Select an image </span>
<input type='file' id={this.imageId()}
accept='.jpg, .png, .jpeg'
onChange={this.onSelectFile}/>
</label>
{ src amp;amp;
<button className='btn btn-success btn-upload'
type='button' id={this.imageId()}
disabled={!src}
onClick={() => this.uploadImage()}>
Upload Image
</button>
}
{ src amp;amp;
<ReactCrop src={src}
crop={crop}
ruleOfThirds
onImageLoaded={this.onImageLoaded}
onComplete={this.onCropComplete}
onChange={this.onCropChange} />
}
{ croppedImageUrl amp;amp;
<div className='img-preview-container' id={this.imageId()}>
<div className='img-preview' id={this.imageId()}
style={{'backgroundImage': 'url(' croppedImageUrl ')'}}>
</div>
{this.renderSpinningCircle()}
</div>
}
{this.renderImageStatus()}
</div>
)
}
}