【问题标题】:Function changes data of input array函数改变输入数组的数据
【发布时间】:2020-03-04 17:07:38
【问题描述】:

我正在制作一个测验应用程序。除了对我的数组进行洗牌的功能外,一切都运行良好,因此每次的答案似乎都是随机的。这是代码。

  shuffleArray() {
    let array = this.state.answerArray;
    for (let i = array.length - 1; i > 0; i--) {
      const j = Math.floor(Math.random() * (i + 1));
      [array[i], array[j]] = [array[j], array[i]];
    }
    return array;
  }

获取和存储工作正常,但每当我调用 shuffleArray 函数时,我的原始数组 (answerArray) 也会像 shuffledArray 一样随机播放。

我在获取我的数据后在 setState 之后调用函数

this.setState(
          {
            qid: _id,
            question: question,
            correct_answer: correct_answer,
            answerArray: [
              correct_answer,
              answer1 || " ",
              answer2 || " ",
              answer3 || " "
            ]
          },
          () => {
            this.setState({
              shuffledArray: this.shuffleArray()
            });
          }
        );

知道为什么两个数组都洗牌吗?

【问题讨论】:

    标签: javascript reactjs


    【解决方案1】:

    我们看shuffleArray

     shuffleArray() {
        let array = this.state.answerArray;
        for (let i = array.length - 1; i > 0; i--) {
          const j = Math.floor(Math.random() * (i + 1));
          [array[i], array[j]] = [array[j], array[i]];
        }
        return array;
      }
    

    这里的这一行:

     let array = this.state.answerArray;
    

    它不会将this.state.answerArray 的值复制到arrayarraythis.state.answerArray,所以通过修改 array 来修改 this.state.answerArray

    您可以使用spread syntax 复制您的数组:

    let array = [...this.state.answerArray];
    

    但是为什么?你可能会问。

    嗯,数组是mutable(对象和函数也是如此),所以赋值是通过引用进行的,而不是复制。

    如果我有一个对象数组我该怎么办?

    Check Josh answer below !

    【讨论】:

    • @F.Frlić 不客气,请花时间阅读我回答中的链接,您将获得 Javascript 方面的宝贵知识,并能够在未来帮助他人!另外,不要忘记接受我的回答:)
    【解决方案2】:

    你正在改变 React 状态返回的数组,这就是原因。您不应该这样做 - 请参阅 here

    改为这样做:

    shuffleArray(array) {
        for (let i = array.length - 1; i > 0; i--) {
          const j = Math.floor(Math.random() * (i + 1));
          [array[i], array[j]] = [array[j], array[i]];
        }
        return array;
      }
    
    () => {
       this.setState({
        shuffledArray: this.shuffleArray([...this.state.answerArray])
      });
    

    这假设您的数组是由原语(数字、字符串)组成的。如果它是由对象组成的,你需要这样做:

    this.shuffleArray(this.state.answerArray.map(answer => {...answer}))
    

    如果这些对象包含其他对象,那么您应该使用_.cloneDeep 对其进行深度克隆。这是 Lodash 实用程序库中的一种方法,它递归地克隆对象以提供真正的深层副本。

    数组和对象在 JavaScript 中通过引用传递。而且 React 的状态不是克隆的,你得到的是对状态对象的真实引用。

    您在代码中从 React 获得 实际 状态对象,因此 React 不需要对状态进行深入比较。它只需要检查对象引用。

    如果您有兴趣了解更多信息,请查看“Avoiding global mutable state in Browser JS”和文章“Shun the mutant - the case for const”中的“理解对象引用”部分。

    【讨论】:

    • 嗨乔希。谈论虚构对象和深度克隆是个好主意。我可以建议您在回答中链接库中的方法时谈论 lodash 吗?您不会希望读者认为它是原生 javascript 方法 ^^
    • 仅供参考,如果有人需要有关由对象组成的数组的帮助,我会将您的答案链接到我的答案中;)
    猜你喜欢
    • 2016-05-11
    • 1970-01-01
    • 2013-03-09
    • 1970-01-01
    • 1970-01-01
    • 2016-05-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多