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

React Native onPress调用带参自定义Hook报Invalid Hook Call错误如何解决

错误原因
  • React官方明确规定Hook只能在函数组件的顶层作用域调用,不允许在事件回调、普通函数等嵌套逻辑内调用。你在点击事件触发的pokemonsData函数内调用usePokemonAttributes,违反了该规则,所以会抛出Invalid Hook Call错误。
修复方案

将自定义Hook移到组件顶层,新增一个状态存储选中的宝可梦URL,点击时更新这个状态触发Hook重新请求即可。

第一步:修改组件代码

const PokemonListItem: React.FC<PokemonItemProps> = ({dataPokemon}) => {
  const [modalVisible, setModalVisible] = useState(false);
  // 新增状态存储选中的宝可梦url,初始为空
  const [selectedPokemonUrl, setSelectedPokemonUrl] = useState<string>('');
  // Hook移到组件顶层调用,传入选中的url
  const {data: pokemon, isLoading} = usePokemonAttributes(selectedPokemonUrl);

  // 点击事件仅更新选中的url
  const pokemonsData = (chosenPokemonUrl: string) => {
    setSelectedPokemonUrl(chosenPokemonUrl);
  };

  // 监听请求返回的数据,有数据时打开弹窗
  useEffect(() => {
    if(pokemon) {
      setModalVisible(true);
      console.log(pokemon);
    }
  }, [pokemon])
    
  return (
    <View>
      <TouchableOpacity onPress={() => pokemonsData(dataPokemon.url)}>
        <Text style={styles.pokemonListItem}>{dataPokemon.name}</Text>
      </TouchableOpacity>
      {/* 后续可在此处添加Modal组件,用modalVisible控制显隐,用isLoading做加载态展示 */}
    </View>
  );
};

第二步:优化自定义Hook(修复请求中止异常问题)

你当前的abortController每次组件渲染都会重新创建,无法正确匹配之前的请求中止逻辑,调整到useEffect内部声明即可:

const usePokemonAttributes = (pokemonUrl: string): IusePokemonAttributes => {
  const [isLoading, setLoading] = useState(false);
  const [data, setData] = useState<IPokemonAttributes>();
  const [error, setError] = useState('');

  const fetchingPokemonAttributes = async (abortSignal: AbortSignal) => {
    if(!pokemonUrl) return; // url为空时不发起无效请求
    setLoading(true);
    try {
      const response = await fetch(`${urls.baseUrl + pokemonUrl}`, {
        signal: abortSignal,
      });
      const json = await response.json();
      setData(json);
    } catch (error) {
      setError(error.message);
    } finally {
      setLoading(false);
    }
  };

  useEffect(() => {
    const abortController = new AbortController();
    fetchingPokemonAttributes(abortController.signal);

    return () => {
      abortController.abort();
    };
  }, [pokemonUrl]);
  return {data, error, isLoading};
};

内容的提问来源于stack exchange,提问作者Matko Milić

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 14:54:02