使用 apollo hooks 和太多 re renders 的一般建议
General Advice with apollo hooks and too many re renders
背景:我正在尝试使用 DropZone 实现文件上传到 s3 和 graphql 服务预签名 url 用于放置和获取,虽然它可能不完美但确实有效。我现在遇到的问题是,当我添加 useMutation 以将结果推送到写入 mongodb 数据库的 graphlql 端时,我得到了太多的重新渲染,因此正在寻找有关如何真正理解这里发生的事情的建议。一旦我没有 addFileS3(file) addFileS3(file) addFileS3(file) 调用 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>
);
};
您在渲染 'flow' 期间发出 axios 请求,而不是在事件 handler/chain 中。它被调用,改变状态并导致下一次重新渲染 - 无限循环。
突变和惰性查询都可以使用 onCompleted
处理程序。这是 chain/invoke 下一个操作的位置(使用 data
结果参数)。
... 否则 hanlder 不应该 return 任何东西 (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),为了清楚起见没有放置。
为了提高可读性和优化(限制重新渲染)...我会将几乎所有(处理)移动到单独的子组件中 - 将 acceptedFiles
作为 prop 传递,在内部渲染上传按钮。
背景:我正在尝试使用 DropZone 实现文件上传到 s3 和 graphql 服务预签名 url 用于放置和获取,虽然它可能不完美但确实有效。我现在遇到的问题是,当我添加 useMutation 以将结果推送到写入 mongodb 数据库的 graphlql 端时,我得到了太多的重新渲染,因此正在寻找有关如何真正理解这里发生的事情的建议。一旦我没有 addFileS3(file) addFileS3(file) addFileS3(file) 调用 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>
);
};
您在渲染 'flow' 期间发出 axios 请求,而不是在事件 handler/chain 中。它被调用,改变状态并导致下一次重新渲染 - 无限循环。
突变和惰性查询都可以使用 onCompleted
处理程序。这是 chain/invoke 下一个操作的位置(使用 data
结果参数)。
... 否则 hanlder 不应该 return 任何东西 (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),为了清楚起见没有放置。
为了提高可读性和优化(限制重新渲染)...我会将几乎所有(处理)移动到单独的子组件中 - 将 acceptedFiles
作为 prop 传递,在内部渲染上传按钮。