You need to enable JavaScript to run this app. React Native Stack导航切屏时GameScreen State未正确重置
优惠活动
大模型
产品
解决方案
定价
更多

React Native Stack导航切屏时GameScreen State未正确重置

异常根因定位
  • require('../data/challenges.json') 在React Native环境中是模块系统托管的全局缓存单例,每次调用不会生成新的JSON副本,所有引用指向同一块内存中的原始对象。
  • 首次进入游戏界面时,你在playChallenge、fillInChallenge流程中直接对这个缓存单例的对象属性做原地修改:把原本带p(1)、sips(2,4)占位符的原始文本,永久替换成了随机填充的实际值。
  • 二次进入游戏界面时,useState初始化逻辑再次执行require读取,拿到的还是第一次被修改过的缓存对象,自然不会再出现未填充的原始占位符文本。
  • 代码中多处共享引用的操作加剧了这个问题:
    • 如果shuffle工具函数内部直接对入参数组做原地乱序,会直接修改传入的缓存数组结构
    • playChallenge中直接给currentChallenges[0]重新赋值、对数组做splice插入,没有做拷贝隔离
    • popChallengeHandler中的[...challenges]只是数组浅拷贝,数组内的对象元素依然和全局JSON缓存共享引用,修改时依然会污染源对象
    • 当前fillInChallenge实现存在明显疏漏:没有把待处理的挑战对象作为入参传入,仅把players参数传给了fillInChoice,填充逻辑没有和当前挑战的文本内容绑定
修复方案
  • 读取JSON数据源后第一时间生成独立深拷贝副本,彻底切断和模块缓存对象的引用关联:
    const [challenges, setChallenges] = useState(() => {
      // 读取模块缓存的原始JSON
      const rawDeck = require('../data/challenges.json').deck;
      // 深拷贝生成全新的操作副本,后续所有操作都不会影响原缓存
      const copiedDeck = JSON.parse(JSON.stringify(rawDeck));
      // 所有过滤、乱序、填充操作都在copiedDeck上执行
      const filteredDeck = copiedDeck.filter(challenge => players.length >= playersNeeded(challenge));
      return playChallenge(shuffle(filteredDeck));
    });
    
  • 修正shuffle工具函数的实现逻辑,确保乱序操作不会修改入参原数组:
    // 修正后的shuffle示例
    export const shuffle = (sourceArr) => {
      // 先拷贝一层数组,避免直接修改原数组
      const arr = [...sourceArr];
      for (let i = arr.length - 1; i > 0; i--) {
        const randomIndex = Math.floor(Math.random() * (i + 1));
        [arr[i], arr[randomIndex]] = [arr[randomIndex], arr[i]];
      }
      return arr;
    }
    
  • 修正fillInChallenge的入参逻辑,确保填充操作在独立对象副本上执行,不直接修改原对象:
    const fillInChallenge = (challenge) => {
      // 先创建挑战对象的浅拷贝
      const copiedChallenge = {...challenge};
      // 把当前挑战的文本内容、玩家列表传给替换函数完成占位符替换
      const filledText = fillInChoice(copiedChallenge.initialRound, players);
      // 把填充后的文本写回拷贝对象,不影响原缓存
      copiedChallenge.initialRound = filledText;
      return copiedChallenge;
    }
    
  • 调整playChallenge逻辑,确保所有数组操作都是基于新数组执行,不做原地修改:
    const playChallenge = (currentChallenges) => {
      const [firstChallenge, ...restChallenges] = currentChallenges;
      const processedFirst = fillInChallenge(firstChallenge);
      // 把下一轮的挑战插入到队列里,生成全新的数组
      const newQueue = [processedFirst, ...restChallenges];
      processedFirst.nextRounds.forEach(round => {
        newQueue.splice(round[0], 0, {
          initialRound: round[1],
          nextRounds: []
        })
      })
      return newQueue;
    }
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.05 01:54:04