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

运行Nav.test.js时fakeCountryCollection意外变更的原因排查求助

问题分析与解决方案

这个问题的核心是JavaScript引用类型的特性在搞鬼!咱们一步步拆解清楚:

  • 你定义的fakeCountryCollection是包含对象的数组,这类属于引用类型。当执行app.setState({'countryCollection': fakeCountryCollection})时,并没有把数组和对象复制一份给组件state,只是传递了它们的内存引用。
  • 再看clickNavDropdown方法:你直接从state取出countryCollection后,修改了数组内对象的showSubNav属性。因为这个数组和原fakeCountryCollection指向同一块内存,修改操作直接同步到了原变量上。
  • 加上测试里循环调用clickNavDropdown,所有修改都会累积到fakeCountryCollection,所以后面something else块输出的就是被篡改后的值了。

修复步骤

1. 先修复Nav.js中的clickNavDropdown方法(避免直接修改state引用)

React官方明确推荐不要直接修改state对象,应该创建新副本再更新。可以改成两种写法:

写法一(扩展运算符浅拷贝):

clickNavDropdown(countryCounter){
  // 创建数组的浅拷贝
  let countryCollection = [...this.state.countryCollection];
  // 对要修改的对象也创建副本,避免直接修改原引用
  countryCollection[countryCounter] = {
    ...countryCollection[countryCounter],
    showSubNav: !countryCollection[countryCounter].showSubNav
  };
  this.setState({'countryCollection': countryCollection});
}

写法二(用Array.map更简洁):

clickNavDropdown(countryCounter){
  this.setState(prevState => ({
    countryCollection: prevState.countryCollection.map((item, index) => 
      index === countryCounter 
        ? {...item, showSubNav: !item.showSubNav}
        : item
    )
  }));
}

2. 修复测试代码(隔离不同测试块的数据源)

为了避免不同describe块互相干扰,每次测试都应该使用全新的fakeCountryCollection副本。可以把它封装成一个函数,每次调用都返回新数组:

describe('test nav.js', function () {
  // 用函数返回新副本,每次调用都是独立的
  const getFakeCountryCollection = () => [
    {value: 'england', count: 2, showSubNav: true}, 
    {value: 'canada', count: 0, showSubNav: false}, 
    {value: 'thailand', count: 0, showSubNav: true}, 
    {value: 'hongkon', count: 0, showSubNav: true}
  ];

  describe('function clickNavDropdown', function () {
    let app = shallow(<Nav/>);
    // 获取新的独立副本
    let fakeCollection = getFakeCountryCollection();
    app.setState({'countryCollection': fakeCollection});
    let countryCollection = app.state('countryCollection');
    for (let [index, eachCollection] of countryCollection.entries()) {
      app.instance().clickNavDropdown(index);
      it('iterator the countryCollection in: '+index, function () { ... });
    }
  });

  describe('something else', function () {
    // 这里也调用函数获取全新副本
    console.log('fakeCountryCollection: ', getFakeCountryCollection());
    ...
  });
});

这样处理后,不同测试块的数据源完全隔离,就不会再出现意外修改的情况啦!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 03:41:51