问题描述
大家好。我是那种喜欢在我的代码中消除警告的程序员,这让我很难过。所以我来描述一下情况。
我正在使用极好的库 react-dropzone 为用户提供文件拖放库。有时会出现用户可以提供多个文件的情况;其他时候,用户一次只能上传一个。我喜欢用户能够更改要上传的文件,我也喜欢他们查看已上传的文件。所以我写了一个 TypeScript 文件,它从 dropzone 组件中获取 inputRef,获取文件,甚至将它们作为表格列出。代码有效。
唯一让我烦恼的是它产生了一个我无法消除的警告。看到 onDrop 末尾的 [myFiles,props.multiple]
行了吗?它给了我以下警告:
Line 61:5: React Hook React.useCallback has a missing dependency: 'inputRef'. Either include it or remove the dependency array react-hooks/exhaustive-deps
是的,onDrop 依赖于 inputRef,因为它使用 inputRef 来改变拖放文件列表,但 inputRef ref 变量仅由 useDropzone 创建,它利用 onDrop 作为其参数之一 - 所以我们有一个循环依赖。除了详尽的 deps 警告外,哪个有效。
问题是,如果我将 inputRef 添加到 [myFiles,props.multiple]
数组,我得到:
Block-scoped variable 'inputRef' used before its declaration.
因为 inputRef 是调用 useDropZone 返回的常量之一。
如果我尝试在 onDrop 声明之前将调用移动到 useDropzone,我会得到(惊奇,惊奇):
Block-scoped variable 'onDrop' used before its declaration.
基本上,onDrop 依赖于由 useDropZone 创建的引用,
那我现在该怎么办?不,我不想让警告静音:它的存在是有原因的。而且 React Hooks 似乎有效,所以我对非 Hooks 解决方案不感兴趣。感谢所有建议。
import React,{ useEffect,useMemo } from "react";
import { Button } from "react-bootstrap";
import { useDropzone } from "react-dropzone";
var path = require("path");
/*
// This is a drag and drop components integrating ideas from the following
// sources:
//
// 1.How to actually accept a file (and react to it):
// https://codesandBox.io/s/removable-drop-zone-82km9
//
// 2. How to colour it depending on whether files are accepted or rejected:
// https://react-dropzone.js.org/ "Using inline styles"
//
// 3. Getting a ref in there that can be used outside.
// https://github.com/react-dropzone/react-dropzone/issues/838
*/
interface Props {
setref: any;
multiple: boolean;
existfile?: string;
}
function DropZoneComponent(props: Props) {
const [myFiles,setMyFiles] = React.useState<any>([]);
const onDrop = React.useCallback(
(accepted: any,rejected: any,event: any) => {
if (props.multiple) {
setMyFiles([...myFiles,...accepted]);
} else {
setMyFiles([...accepted]);
}
if (event.type === "drop") {
const dt = new DataTransfer();
const existfiles = Array.from(inputRef!.current!.files!);
if (props.multiple) {
for (let existfile of existfiles) {
dt.items.add(existfile);
}
}
for (let file of accepted) {
dt.items.add(file); // Add only file name not matched files
}
inputRef!.current!.files! = dt.files; // Overwrite files
} else {
const dt = new DataTransfer();
if (props.multiple) {
for (let existfile of myFiles) {
dt.items.add(existfile); // Add only file name not matched files
}
}
for (let existfile of accepted) {
dt.items.add(existfile); // Add only file name not matched files
}
inputRef!.current!.files! = dt.files; // Overwrite files
}
},[myFiles,props.multiple]
);
const {
getRootProps,getInputProps,inputRef,isDragActive,isDragAccept,isDragReject,} = useDropzone({
noKeyboard: true,maxSize: 20971520,multiple: props.multiple,maxFiles: props.multiple ? 0 : 1,accept: "image/*,.pdf",onDrop,});
const handleRemoveFile = React.useCallback(
(index) => {
const dt = new DataTransfer();
let files = Array.from(inputRef!.current!.files!);
files.splice(index,1);
for (let file of files) {
dt.items.add(file);
}
inputRef!.current!.files! = dt.files; // Overwrite files
setMyFiles(Array.from(dt.files)); // Set states to render file list
},[inputRef]
);
const files = React.useMemo<any>(
() =>
myFiles.map((file: any,index: number) => (
<tr>
{" "}
<th key={file.name}>{file.name}</th>
<td>{file.size}</td>
<td>
<Button
variant="outline-success"
onClick={() => handleRemoveFile(index)}
>
Remove file
</Button>
</td>{" "}
</tr>
)),[handleRemoveFile,myFiles]
);
const baseStyle = {
flex: 1,display: "flex",alignItems: "center",padding: "20px",borderWidth: 2,borderRadius: 2,borderColor: "#eeeeee",borderStyle: "dashed",backgroundColor: "#fafafa",color: "#bdbdbd",outline: "none",transition: "border .24s ease-in-out",};
const activeStyle = {
borderColor: "#2196f3",};
const acceptStyle = {
borderColor: "#00e676",};
const rejectStyle = {
borderColor: "#ff1744",};
const style = useMemo(
() => ({
...baseStyle,...(isDragActive ? activeStyle : {}),...(isDragAccept ? acceptStyle : {}),...(isDragReject ? rejectStyle : {}),}),[
isDragActive,acceptStyle,activeStyle,baseStyle,rejectStyle,]
);
useEffect(() => {
if (inputRef.current !== props.setref.current) {
props.setref.current = inputRef.current;
}
},[props.setref,myFiles]);
const dropText = !props.multiple
? "Drag and drop a file here,or click to select a file."
: "Drag and drop some files here,or click to select files.";
let labelText = props.existfile ? (
<p>
{dropText}
<br />
Existing file: {path.basename(props.existfile)}
</p>
) : (
<p>{dropText}</p>
);
return (
<section className="container">
<div {...getRootProps({ className: "dropzone",style: style })}>
<input {...getInputProps()} />
{labelText}
</div>
{files.length > 0 ? (
<div>
<table className="table table-hover plan-table">
<thead className="plan-table-thead">
<tr className="plan-table-tr">
<th className="plan-table-th col">File name</th>
<th className="plan-table-th col">Length (bytes)</th>
<th className="plan-table-th col"></th>
</tr>
</thead>
<tbody className="plan-table-tbody">{files}</tbody>
</table>
</div>
) : (
""
)}
</section>
);
}
export default DropZoneComponent;
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)