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

React Native useEffect监听selectedSet变更时调用函数陷入死循环

问题根源

你当前的代码存在两个核心问题:

  • 状态更新的异步性:setSelectedSet 是异步更新状态的操作,调用后立刻执行navigation.navigate时,拿到的pokemonCards一定是上一次渲染的旧值,不是最新请求返回的卡片数据。
  • 无限循环的诱因:你的useEffect没有对selectedSet做空值判断,初始渲染时selectedSet是空字符串,会直接触发接口请求。如果接口返回的空结果每次引用地址不同(哪怕内容都是空数组),setPokemonCards会触发组件重渲染,如果你其他逻辑里存在依赖pokemonCards修改selectedSet的代码,就会形成「selectedSet更新→发起请求→更新pokemonCards→selectedSet被修改」的无限循环。还有一种常见场景是你循环渲染TouchableHighlight时,没有用useCallback包裹onPress的处理函数,每次组件重渲染都会生成新的函数引用,导致列表项不必要的重渲染,放大了状态更新的副作用。

解决方案

最优方案(从根源避免循环)

完全可以去掉多余的useEffect和冗余的状态,直接在点击事件里处理请求,拿到结果后再跳转:

// 点击处理函数用useCallback包裹避免不必要的重渲染
const handleSetClick = useCallback(async (pokemonSet) => {
  // 直接发起卡片请求
  const cards = await PokemonTCG.findCardsByQueries({ 
    q: 'set.id:' + pokemonSet.id, 
    pageSize: 10 
  })
  // 请求成功后再跳转,直接传递拿到的卡片数据
  navigation.navigate("SetDetails", { 
    setID: pokemonSet.id, 
    pokemonSetDetails: pokemonSet, 
    pokemonCards: cards 
  });
}, [navigation])

// 渲染TouchableHighlight
<TouchableHighlight 
  key={pokemonSet.id} 
  onPress={() => handleSetClick(pokemonSet)}
>

兼容原有逻辑的修改方案

如果你一定要保留原来的useEffect写法,需要做两处修改:

  1. 给useEffect加空值判断,selectedSet为空时不发起请求
  2. 跳转逻辑移到useEffect里,等pokemonCards更新完成后再跳转,不要在点击时立刻跳转
const [pokemonCards, setPokemonCards] = useState([]);
const [selectedSet, setSelectedSet] = useState("");
// 新增状态存储选中的集合完整信息
const [selectedSetInfo, setSelectedSetInfo] = useState(null);

useEffect(() => {
  // 空值直接返回,不发起请求
  if (!selectedSet || !selectedSetInfo) return;

  const getPokemonCards = async () => {
    const cards = await PokemonTCG.findCardsByQueries({ 
      q: 'set.id:' + selectedSet, 
      pageSize: 10 
    })
    setPokemonCards(cards);
    // 拿到卡片数据后再执行跳转
    navigation.navigate("SetDetails", { 
      setID: selectedSet, 
      pokemonSetDetails: selectedSetInfo, 
      pokemonCards: cards 
    });
  }
  getPokemonCards();
}, [selectedSet, selectedSetInfo, navigation]);

// 点击时只存储选中的集合信息,不做跳转
<TouchableHighlight 
  key={pokemonSet.id} 
  onPress = {() => {
    setSelectedSet(pokemonSet.id);
    setSelectedSetInfo(pokemonSet);
  }}
>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 03:06:03