You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在React的useCallback钩子中正确使用useAuthenticatedFetch?解决调用错误

问题:如何在useCallback中正确使用Shopify的useAuthenticatedFetch钩子?

我持续收到如下错误,useAuthenticatedFetch是Shopify提供的钩子,返回原生JS的fetch方法,请问怎么在useCallback里正确调用它?

Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:

原错误代码:

function DropZoneExample() {
    const [files, setFiles] = useState([]);
    
    const handleDropZoneDrop = useCallback( async (_dropFiles, acceptedFiles, _rejectedFiles) => {
            setFiles((files) => [...files, ...acceptedFiles]);
            let formData = new FormData();
            formData.append('files', acceptedFiles)
            let options = {
                method: 'POST',
                body: formData
            };
            await useAuthenticatedFetch('/api/files', options) // 错误:在回调内调用钩子
        },
        [],
    );

    const validImageTypes = ['image/gif', 'image/jpeg', 'image/png'];

    const fileUpload = !files.length && <DropZone.FileUpload />;
    const uploadedFiles = files.length > 0 && (
        <div style={{padding: '0'}}>
            <Stack vertical>
                {files.map((file, index) => (
                    <Stack alignment="center" key={index}>
                        <Thumbnail
                            size="small"
                            alt={file.name}
                            source={
                                validImageTypes.includes(file.type)
                                    ? window.URL.createObjectURL(file)
                                    : NoteMinor
                            }
                        />
                        <div>
                            {file.name}{' '}
                            {file.size} bytes
                        </div>
                    </Stack>
                ))}
            </Stack>
        </div>
    );

    return (
        <DropZone onDrop={handleDropZoneDrop} dropOnPage={true}>
            {uploadedFiles}
            {fileUpload}
        </DropZone>
    );
}

错误原因

React钩子规则明确要求:钩子只能在函数组件的顶层作用域调用,或在自定义钩子的顶层调用,不能嵌套在普通回调、条件判断、循环等逻辑内部。你在useCallback的回调函数里调用useAuthenticatedFetch,违反了这个规则,因此触发无效钩子调用错误。

正确实现方案

在组件顶层调用useAuthenticatedFetch拿到认证后的fetch方法,再在useCallback的回调中使用这个方法:

function DropZoneExample() {
    const [files, setFiles] = useState([]);
    // 1. 在组件顶层调用钩子,获取认证后的fetch实例
    const authenticatedFetch = useAuthenticatedFetch();
    
    const handleDropZoneDrop = useCallback( async (_dropFiles, acceptedFiles, _rejectedFiles) => {
            setFiles((files) => [...files, ...acceptedFiles]);
            let formData = new FormData();
            formData.append('files', acceptedFiles)
            let options = {
                method: 'POST',
                body: formData
            };
            // 2. 使用拿到的authenticatedFetch发起请求
            await authenticatedFetch('/api/files', options)
        },
        [authenticatedFetch], // 3. 将authenticatedFetch加入依赖数组,确保回调拿到最新实例
    );

    const validImageTypes = ['image/gif', 'image/jpeg', 'image/png'];

    const fileUpload = !files.length && <DropZone.FileUpload />;
    const uploadedFiles = files.length > 0 && (
        <div style={{padding: '0'}}>
            <Stack vertical>
                {files.map((file, index) => (
                    <Stack alignment="center" key={index}>
                        <Thumbnail
                            size="small"
                            alt={file.name}
                            source={
                                validImageTypes.includes(file.type)
                                    ? window.URL.createObjectURL(file)
                                    : NoteMinor
                            }
                        />
                        <div>
                            {file.name}{' '}
                            {file.size} bytes
                        </div>
                    </Stack>
                ))}
            </Stack>
        </div>
    );

    return (
        <DropZone onDrop={handleDropZoneDrop} dropOnPage={true}>
            {uploadedFiles}
            {fileUpload}
        </DropZone>
    );
}

关键改动说明

  • 将useAuthenticatedFetch()移到组件顶层,获取认证后的fetch实例authenticatedFetch
  • 在handleDropZoneDrop中调用authenticatedFetch代替直接调用钩子
  • 将authenticatedFetch加入useCallback的依赖数组,确保回调能拿到最新的fetch实例

内容的提问来源于stack exchange,提问作者pyRabbit

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 23:42:51