【问题标题】:How to run a function only once in react如何在反应中只运行一次功能
【发布时间】:2021-02-20 18:12:37
【问题描述】:

我正在开发一个简单的测验应用程序。我有一个本地数组,其中包含每次随机顺序的问题。每次运行 handleAnswerOptionClick 时都会触发以不同顺序打乱数组的函数。

怎样才能运行一次arrayShuffle函数?

我的猜测是我可以为此使用 useEffect,但我还没有让它工作。它抱怨它没有不同的依赖关系。

 useEffect(() => {
    arrayShuffle(questions);
  }, []);

代码:CodeSandox

测验容器:

import React, { useState, useEffect } from "react";

export const QuizContainer = () => {
  const questions = [
    {
      questionText: "What is the capital of France?",
      answerOptions: [
        { option: "New York", isCorrect: false },
        { option: "London", isCorrect: false },
        { option: "Paris", isCorrect: true },
        { option: "Dublin", isCorrect: false }
      ]
    },
    {
      questionText: "Who is CEO of Tesla?",
      answerOptions: [
        { option: "Jeff Bezos", isCorrect: false },
        { option: "Elon Musk", isCorrect: true },
        { option: "Bill Gates", isCorrect: false },
        { option: "Tony Stark", isCorrect: false }
      ]
    },
    {
      questionText: "The iPhone was created by which company?",
      answerOptions: [
        { option: "Apple", isCorrect: true },
        { option: "Intel", isCorrect: false },
        { option: "Amazon", isCorrect: false },
        { option: "Microsoft", isCorrect: false }
      ]
    },
    {
      questionText: "How many Harry Potter books are there?",
      answerOptions: [
        { option: "1", isCorrect: false },
        { option: "4", isCorrect: false },
        { option: "6", isCorrect: false },
        { option: "7", isCorrect: true }
      ]
    }
  ];

  const [currentQuestion, setCurrentQuestion] = useState(0);
  const [showScore, setShowScore] = useState(false);
  const [score, setScore] = useState(0);

  // Event handlers
  const handleAnswerOptionClick = (isCorrect) => {
    if (isCorrect) {
      setScore(score + 1);
    }

    const nextQuestion = currentQuestion + 1;
    nextQuestion < questions.length
      ? setCurrentQuestion(nextQuestion)
      : setShowScore(true);
  };

  // ShuffleArray
  const arrayShuffle = function (arr) {
    let newPos, temp;
    for (let i = arr.length - 1; i > 0; i--) {
      newPos = Math.floor(Math.random() * (i + 1));
      temp = arr[i];
      arr[i] = arr[newPos];
      arr[newPos] = temp;
    }
    return arr;
  };

  const newArray = arrayShuffle(questions);
  console.log(newArray);

  return (
    <>
      <h1>QuizContainer</h1>
      {showScore ? (
        <p>
          You scored {score} out of {questions.length}
        </p>
      ) : (
        <>
          <p>
            Question {currentQuestion + 1}/{questions.length}
          </p>

          <p>{questions[currentQuestion].questionText}</p>

          <div>
            {questions[currentQuestion].answerOptions.map(
              (answerOption, index) => (
                <div key={index}>
                  <button
                    onClick={() =>
                      handleAnswerOptionClick(answerOption.isCorrect)
                    }
                  >
                    {answerOption.option}
                  </button>
                </div>
              )
            )}
          </div>
        </>
      )}
    </>
  );
};

请问我是否需要澄清,以及你们是否认为我的处理方式正确。

先谢谢了,

埃里克

【问题讨论】:

    标签: javascript reactjs ecmascript-6 react-hooks


    【解决方案1】:

    两件事:

    1. 如果您希望函数在挂载时运行,请使用带有空依赖项数组的 useEffect,并且您可以放心地忽略这种情况下的 linter 警告并且仅在这种情况下
    2. 这不是(据我所知)您想要的:您希望在页面加载时运行一次,然后再也不运行。

    如果是这样,那么甚至没有必要将其放入组件中。将其拉出到它自己的顶级事物中:

      const questions = [
        {
          questionText: "What is the capital of France?",
          answerOptions: [
            { option: "New York", isCorrect: false },
            { option: "London", isCorrect: false },
            { option: "Paris", isCorrect: true },
            { option: "Dublin", isCorrect: false }
          ]
        },
        {
          questionText: "Who is CEO of Tesla?",
          answerOptions: [
            { option: "Jeff Bezos", isCorrect: false },
            { option: "Elon Musk", isCorrect: true },
            { option: "Bill Gates", isCorrect: false },
            { option: "Tony Stark", isCorrect: false }
          ]
        },
        {
          questionText: "The iPhone was created by which company?",
          answerOptions: [
            { option: "Apple", isCorrect: true },
            { option: "Intel", isCorrect: false },
            { option: "Amazon", isCorrect: false },
            { option: "Microsoft", isCorrect: false }
          ]
        },
        {
          questionText: "How many Harry Potter books are there?",
          answerOptions: [
            { option: "1", isCorrect: false },
            { option: "4", isCorrect: false },
            { option: "6", isCorrect: false },
            { option: "7", isCorrect: true }
          ]
        }
      ];
    
      const arrayShuffle = function (arr) {
        let newPos, temp;
        for (let i = arr.length - 1; i > 0; i--) {
          newPos = Math.floor(Math.random() * (i + 1));
          temp = arr[i];
          arr[i] = arr[newPos];
          arr[newPos] = temp;
        }
        return arr;
      };
    
      const newArray = arrayShuffle(questions);
    
      export const QuizContainer = () => {
        /* rest of component */
      }
    

    如果您确实想重新运行它但又想控制这样做,您可以将其置于状态:

    export const QuizContainer = () => {
      const [shuffled, setShuffled] = useState(arrayShuffle(questions));
      const reShuffle = () => setShuffled(arrayShuffle(questions));
      /* rest of the component */
    }
    

    但一般来说,不要使用静态常量来混淆组件定义,这些常量在整个页面浏览中都保持不变。

    【讨论】:

    • 关于(1):只要questions不改变,添加到dependencies数组就没有错。
    • @JonasWilms 绝对是,但我相信你知道我们每天会收到 50 个关于 linter 抱怨空依赖数组的问题。
    • 啊,我明白了!这很简单,因为它在组件内部。我将进一步研究 useEffect 依赖项,但感谢您为我指明正确的方向。 // 埃里克@JaredSmith
    • @erikos93 我很高兴,是的:请记住,任何不属于钩子的代码(以及钩子中的很多内容)都会在每次安装组件时重新运行,并且每次应用程序状态发生变化时,组件都可能会重新挂载(有一些方法可以改变它,但我们正误入歧途)。
    【解决方案2】:

    你只能像这样一次运行一个函数

    import React, { useEffect, useState } from "react";
    
    const Component = () => {
        
        const [functionCount,setFunctionCount] = useState(0);
    
        useEffect(() => {
            if (functionCount == 0) { MyFunction() }
        })
        
       const MyFunction = () => {
           // Code here
           setFunctionCount(functionCount + 1);
       }
       
       return (<h1> {functionCount} </h1>);
    }
    
    export default Component;
    

    【讨论】:

    • 如果状态会改变,组件将被重新渲染并且useEffect重新运行
    猜你喜欢
    • 1970-01-01
    • 2016-05-30
    • 2021-06-17
    • 2019-11-12
    • 1970-01-01
    • 2015-07-21
    • 2020-07-06
    • 2020-12-29
    • 2013-07-22
    相关资源
    最近更新 更多