我正在尝试让react-easy-crop发挥作用。该代码成功显示了一个按钮(上传文件),该按钮触发屏幕以选择图片。拍摄照片后,会出现一个新的模式,该模式在图片顶部显示圆形裁剪叠加。目标是调整图片大小并将其保存在croppedImage中,以便我可以将其存储到后端。
当前的问题是“onCropComplete”被一遍又一遍地调用。我可以通过打印语句来看到这一点。拆线
setCroppedAreaPixels(croppedAreaPixels);
解决了问题,尽管尚不清楚为什么会发生这种情况。
任何人都可以帮我解释为什么这个函数不断被调用吗? 我的代码附在下面。
// The `Cropper` component is on the global object as `ReactEasyCrop`. Assign to `Cropper` so we can use it like a ES6 module
window.Cropper = window.ReactEasyCrop;
const { createRoot } = ReactDOM;
const { StrictMode, useEffect, useState, useRef, useCallback } = React;
// Mock `useAxios`
function useAxios() {}
// Mock `useParams`
function useParams() {
return {
id: 1,
}
}
// Mock `getCroppedImg`
function getCroppedImg() {}
const UserDetail = () => {
const { id } = useParams();
const [res, setRes] = useState("");
const [dateJoined, setDateJoined] = useState("");
const [avatar, setAvatar] = useState("");
const [modalState, setModalState] = useState(false);
const api = useAxios();
const inputRef = useRef(null);
const [selectedImage, setSelectedImage] = useState(null);
const [crop, setCrop] = useState({ x: 0, y: 0 });
const [zoom, setZoom] = useState(1);
const [croppedAreaPixels, setCroppedAreaPixels] = useState(null);
const [croppedImage, setCroppedImage] = useState(null);
const showHideClassName = modalState
? "modal display-block"
: "modal display-none";
useEffect(() => {
console.log("useeffect!");
const fetchData = () => {
// make unrelated API call to backend
};
fetchData();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [id]);
const handleFileChange = (event) => {
// works - saves file to selected image and triggers cropping modal
console.log(event.target.files[0].name);
setSelectedImage(event.target.files[0]);
showModal();
};
const handleFileUpload = (event) => {
// function not yet called because problem in onCropComplete
showCroppedImage();
const sendData = () => {
// API call to POST newly cropped image
};
sendData();
hideModal();
};
const showModal = () => {
setModalState(true);
};
const hideModal = () => {
setModalState(false);
};
const onCropComplete = useCallback((croppedArea, croppedAreaPixels) => {
//problematic function, is called infinitely
setCroppedAreaPixels(croppedAreaPixels);
console.log(croppedAreaPixels);
}, []);
const showCroppedImage = useCallback(() => {
//code not working yet, first onCropComplete should work correctly
try {
// Converted async/await function to promise as Stack Snippets does not support async/await when transpiling with Babel as Babel version is too old. See: https://meta.stackoverflow.com/questions/386097/why-wont-this-snippet-with-async-await-work-here-on-stack-overflow-snippet-edit
const croppedImage = getCroppedImg(
selectedImage,
croppedAreaPixels,
0
).then(() => {
console.log("donee", { croppedImage });
setCroppedImage(croppedImage);
});
} catch (e) {
console.error(e);
}
}, [selectedImage, croppedAreaPixels]);
return (
<div className="parent">
<div className="userdetail">
<div className="profilebanner">
<div className="profilepicture">
<img src={avatar} alt="" className="avatar" />
<input
ref={inputRef}
onChange={handleFileChange}
type="file"
style={{ display: "none" }}
/>
<button onClick={() => inputRef.current.click()}>
Upload File
</button>
<div className={showHideClassName}>
<section className="modal-main">
<p align="center">Modal</p>
<div className="cropper">
{selectedImage && (
<Cropper
image={URL.createObjectURL(selectedImage)}
crop={crop}
aspect={5 / 5}
zoom={zoom}
zoomSpeed={4}
maxZoom={3}
zoomWithScroll={true}
showGrid={true}
cropShape="round"
onCropChange={setCrop}
onCropComplete={onCropComplete}
onZoomChange={setZoom}
/>
)}
</div>
<button onClick={handleFileUpload}>Confirm!</button>
<button type="button" onClick={hideModal}>
Close
</button>
</section>
</div>
</div>
</div>
</div>
</div>
);
};
const root = createRoot(document.getElementById("root"));
root.render(<StrictMode><UserDetail /></StrictMode>);
<script crossorigin defer src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin defer src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<script crossorigin defer src="https://unpkg.com/[email protected]/tslib.js"></script>
<!-- tslib assigns its functions to the global object (e.g. `window.__assign`) however React Easy Crop expects it on the tslib object (e.g. `window.tslib.__assign`). This is hacky but allows React Easy Crop to find tslib functions on `window.tslib` -->
<script type="module">window.tslib = window</script>
<script crossorigin defer src="https://unpkg.com/[email protected]/umd/react-easy-crop.js"></script>
<div id="root"></div>
不要在
URL.createObjectURL
组件的 image
属性中调用 Cropper
,而是在设置 selectedImage
状态之前调用它。演示如下:
// The `Cropper` component is on the global object as `ReactEasyCrop`. Assign to `Cropper` so we can use it like a ES6 module
window.Cropper = window.ReactEasyCrop;
const { createRoot } = ReactDOM;
const { StrictMode, useEffect, useState, useRef, useCallback } = React;
// Mock `useAxios`
function useAxios() {}
// Mock `useParams`
function useParams() {
return {
id: 1,
}
}
// Mock `getCroppedImg`
function getCroppedImg() {}
const UserDetail = () => {
const { id } = useParams();
const [res, setRes] = useState("");
const [dateJoined, setDateJoined] = useState("");
const [avatar, setAvatar] = useState("");
const [modalState, setModalState] = useState(false);
const api = useAxios();
const inputRef = useRef(null);
const [selectedImage, setSelectedImage] = useState(null);
const [crop, setCrop] = useState({ x: 0, y: 0 });
const [zoom, setZoom] = useState(1);
const [croppedAreaPixels, setCroppedAreaPixels] = useState(null);
const [croppedImage, setCroppedImage] = useState(null);
const showHideClassName = modalState
? "modal display-block"
: "modal display-none";
useEffect(() => {
console.log("useeffect!");
const fetchData = () => {
// make unrelated API call to backend
};
fetchData();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [id]);
const handleFileChange = (event) => {
// works - saves file to selected image and triggers cropping modal
console.log(event.target.files[0].name);
setSelectedImage(URL.createObjectURL(event.target.files[0]));
showModal();
};
const handleFileUpload = (event) => {
// function not yet called because problem in onCropComplete
showCroppedImage();
const sendData = () => {
// API call to POST newly cropped image
};
sendData();
hideModal();
};
const showModal = () => {
setModalState(true);
};
const hideModal = () => {
setModalState(false);
};
const onCropComplete = useCallback((croppedArea, croppedAreaPixels) => {
//problematic function, is called infinitely
setCroppedAreaPixels(croppedAreaPixels);
console.log(croppedAreaPixels);
}, []);
const showCroppedImage = useCallback(() => {
//code not working yet, first onCropComplete should work correctly
try {
// Converted async/await function to promise as Stack Snippets does not support async/await when transpiling with Babel as Babel version is too old. See: https://meta.stackoverflow.com/questions/386097/why-wont-this-snippet-with-async-await-work-here-on-stack-overflow-snippet-edit
const croppedImage = getCroppedImg(
selectedImage,
croppedAreaPixels,
0
).then(() => {
console.log("donee", { croppedImage });
setCroppedImage(croppedImage);
});
} catch (e) {
console.error(e);
}
}, [selectedImage, croppedAreaPixels]);
return (
<div className="parent">
<div className="userdetail">
<div className="profilebanner">
<div className="profilepicture">
<img src={avatar} alt="" className="avatar" />
<input
ref={inputRef}
onChange={handleFileChange}
type="file"
style={{ display: "none" }}
/>
<button onClick={() => inputRef.current.click()}>
Upload File
</button>
<div className={showHideClassName}>
<section className="modal-main">
<p align="center">Modal</p>
<div className="cropper">
{selectedImage && (
<Cropper
image={selectedImage}
crop={crop}
aspect={5 / 5}
zoom={zoom}
zoomSpeed={4}
maxZoom={3}
zoomWithScroll={true}
showGrid={true}
cropShape="round"
onCropChange={setCrop}
onCropComplete={onCropComplete}
onZoomChange={setZoom}
/>
)}
</div>
<button onClick={handleFileUpload}>Confirm!</button>
<button type="button" onClick={hideModal}>
Close
</button>
</section>
</div>
</div>
</div>
</div>
</div>
);
};
const root = createRoot(document.getElementById("root"));
root.render(<StrictMode><UserDetail /></StrictMode>);
<script crossorigin defer src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin defer src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<script crossorigin defer src="https://unpkg.com/[email protected]/tslib.js"></script>
<!-- tslib assigns its functions to the global object (e.g. `window.__assign`) however React Easy Crop expects it on the tslib object (e.g. `window.tslib.__assign`). This is hacky but allows React Easy Crop to find tslib functions on `window.tslib` -->
<script type="module">window.tslib = window</script>
<script crossorigin defer src="https://unpkg.com/[email protected]/umd/react-easy-crop.js"></script>
<div id="root"></div>