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

React自定义Hook报错:不是函数或返回值不可迭代

问题根源

你犯了一个核心错误:Redux的connect是高阶组件,只能用来包裹React组件,不能用来包装自定义Hook。

你用connect包装useLocalStorageHandler后,导出的已经不是一个Hook函数,而是一个React组件。当你在Submission里像调用Hook一样执行useLocalStorageHandler()时,本质上是在尝试调用一个组件,这就会触发not a function的错误,更不可能返回[state, setState]这样的可迭代数组。

另外看你的代码,useLocalStorageHandler里接收的setTaskSubmissions参数从头到尾没被使用,这部分Redux关联完全是多余的。

修复方案

方案1:移除多余的Redux connect(推荐,因为你没用到Redux)

直接删除所有Redux相关代码,让useLocalStorageHandler回归纯Hook:

import React from 'react';
import { useState, useRef, useEffect } from 'react';

function useLocalStorageHandler(key, defaultValue = '') {
    const [state, setState] = useState(() => {
        // 从localStorage读取,处理初始值
        const storedValue = window.localStorage.getItem(key);
        return storedValue !== null ? storedValue : defaultValue;
    });
    const prevKeyRef = useRef(key);

    useEffect(() => {
        const prevKey = prevKeyRef.current;
        if (prevKey !== key) {
            window.localStorage.removeItem(prevKey);
        }
        prevKeyRef.current = key;
        window.localStorage.setItem(key, state);
    }, [key, state]);

    return [state, setState];
}

export default useLocalStorageHandler;

然后修改Submission组件的导入语句(因为现在是默认导出):

// 把命名导入改成默认导入
import useLocalStorageHandler from '../../../hooks/useLocalStorageHandler';

方案2:如果确实需要在Hook中使用Redux(假设后续会用到)

不要用connect包裹Hook,而是在Hook内部使用Redux的useDispatch和useSelector Hook:

import React from 'react';
import { useState, useRef, useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { setTaskSubmissions } from '../redux/actions/main';

function useLocalStorageHandler(key, defaultValue = '') {
    const dispatch = useDispatch();
    const taskSubmissions = useSelector(state => state.main.taskSubmissions);
    
    const [state, setState] = useState(() => {
        const storedValue = window.localStorage.getItem(key);
        return storedValue !== null ? storedValue : defaultValue;
    });
    const prevKeyRef = useRef(key);

    useEffect(() => {
        const prevKey = prevKeyRef.current;
        if (prevKey !== key) {
            window.localStorage.removeItem(prevKey);
        }
        prevKeyRef.current = key;
        window.localStorage.setItem(key, state);
        
        // 示例:如果需要用dispatch更新Redux状态
        // dispatch(setTaskSubmissions(...))
    }, [key, state, dispatch]);

    return [state, setState];
}

export default useLocalStorageHandler;

同样,Submission组件的导入要改成默认导入,调用方式不变。

额外注意点
  • React Hook必须遵循Hook规则:只能在函数组件或其他自定义Hook的顶层调用,不能在条件、循环里调用。你的Submission组件调用方式是符合规则的,修复后就能正常运行。
  • 初始值读取逻辑可以优化:原代码里window.localStorage.getItem(key) || defaultValue有问题,如果localStorage里存的是'false'、'0'这类 falsy 值,会被错误替换成defaultValue。所以改成判断storedValue !== null更严谨。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 22:50:33