背景。我试图实现一个文件上传与DropZone到s3和graphql服务presigned url的put和get,虽然它可能不是完美的,它确实工作。我现在遇到的问题是,当我添加useMutation将结果推送到graphlql端,写到mongodb数据库时,我得到了太多的重新渲染,所以寻求建议,如何真正理解这里发生的事情。由于我的代码可能是丑陋的上传到s3工作,一旦我没有addFileS3(文件)的addFileS3(文件)是调用useMutation到grpahql写的结果到mongoDB,所以我可以检索文件在以后的点,所以我假设最好的地方是响应从axios。
const DropZone = ({ folderId, folderProps }) => {
const [createS3File] = useMutation(ADD_FILE_S3);
const addFileS3 = (file) => {
createS3File({
variables: {
folderId: folderId,
fileName: file.name,
},
})
.then(({ data }) => {
console.log("data", data);
})
.catch((e) => {
console.log(e);
});
};
const {
acceptedFiles,
getRootProps,
getInputProps,
isDragActive,
isDragAccept,
isDragReject,
} = useDropzone({ accept: "image/*, application/pdf" });
const [
getPutURL,
{ loading: loading_url, error: error_url, data: data_url },
] = useLazyQuery(GET_S3_PUT_URL);
if (loading_url) {
console.log("loading");
} else if (error_url) {
console.log(error_url);
} else if (data_url) {
const results = data_url.PUTURL;
results.map((file) => {
const fileResult = acceptedFiles.filter(function(fileAcc) {
return fileAcc.name === file.name;
});
const options = {
params: {
Key: file.name,
ContentType: file.type,
},
headers: {
"Content-Type": file.type,
},
};
axios
.put(file.url, fileResult[0], options)
.then((res) => {
//once i add the below here or outside axios post it goes mental on uploads
addFileS3(file);
})
.catch((err) => {
});
});
}
const acceptedFilesItems = acceptedFiles.map((file) => {
return (
<li key={file.path}>
{file.path} - {file.size} bytes
</li>
);
});
const uploadDocs = () => {
let files = [];
acceptedFiles.map((file) => {
const fileObj = { name: file.name, type: file.type };
files.push(fileObj);
});
return getS3URLResult(files);
};
const getS3URLResult = async (files) => {
getPutURL({
variables: {
packet: files,
},
});
};
return (
<StyledDropZone>
<div className="container">
<Container
{...getRootProps({ isDragActive, isDragAccept, isDragReject })}
>
<input {...getInputProps()} />
<p>Drag 'n' drop some files here, or click to select files</p>
</Container>
{acceptedFilesItems}
</div>
<button onClick={() => uploadDocs(acceptedFiles)}>Upload</button>
</StyledDropZone>
);
};
你在渲染 "流 "期间提出axios请求,而不是在事件处理链中。它被调用,改变状态,并导致下一次重新渲染--无限循环。
突变和懒惰查询都有可能使用 onCompleted
处理程序。这是一个连锁调用下一个动作的地方(使用 data
结果参数)。)
......另外,hanlder不应该返回任何东西(return getS3URLResult(files);
)--就叫它(getS3URLResult(files);
)或直接 getPutURL
.
可能你要找的是这样的东西。
const DropZone = ({ folderId, folderProps }) => {
const {
acceptedFiles,
getRootProps,
getInputProps,
isDragActive,
isDragAccept,
isDragReject,
} = useDropzone({ accept: "image/*, application/pdf" });
const uploadDocs = () => {
let files = [];
acceptedFiles.map((file) => {
const fileObj = { name: file.name, type: file.type };
files.push(fileObj);
});
console.log("uploadDocs, from acceptedFiles", files);
// return getS3URLResult(files);
getPutURL({
variables: {
packet: files,
},
});
};
const [
getPutURL,
{ loading: loading_url, error: error_url, data: data_url },
] = useLazyQuery(GET_S3_PUT_URL, {
onCompleted: (data) => {
console.log("PUT_URL", data);
const results = data.PUTURL;
results.map((file) => {
const fileResult = acceptedFiles.filter(function(fileAcc) {
return fileAcc.name === file.name;
});
const options = {
params: {
Key: file.name,
ContentType: file.type,
},
headers: {
"Content-Type": file.type,
},
};
axios
.put(file.url, fileResult[0], options)
.then((res) => {
console.log("axios PUT", file.url);
// addFileS3(file);
createS3File({
variables: {
folderId: folderId,
fileName: file.name,
},
})
})
.catch((err) => {
});
});
}
});
const [createS3File] = useMutation(ADD_FILE_S3,{
onCompleted: (data) => {
console.log("ADD_FILE_S3", data);
//setUploadedFiles( uploadedFiles,concat(data.somefilename) );
}
});
const [uploadedFiles, setUploadedFiles] = useState( [] );
const acceptedFilesItems = acceptedFiles.map((file) => {
return (
<li key={file.path}>
{file.path} - {file.size} bytes
</li>
);
});
const renderUploadedFiles ...
return (
<StyledDropZone>
<div className="container">
<Container
{...getRootProps({ isDragActive, isDragAccept, isDragReject })}
>
<input {...getInputProps()} />
<p>Drag 'n' drop some files here, or click to select files</p>
</Container>
{acceptedFilesItems}
{uploadedFiles.length && <div class="success">
{renderUploadedFiles}
</div>}
</div>
<button onClick={() => uploadDocs(acceptedFiles)}>Upload</button>
</StyledDropZone>
);
};
一些优化应该被添加(useCallback),而不是为了清晰而放置。
为了更多的可读性和优化(限制reerenderings)......。我会把几乎所有的(处理)都移到单独的子组件中--通过 acceptedFiles
作为道具,在里面渲染上传按钮。