【问题标题】:获取数组 useState React 中的下一个对象
【发布时间】:2022-01-23 13:46:01
【问题描述】:

我正在构建一个测验网站作为 React 的练习,并希望能够通过按钮更改问题。当我手动将 useState(0) 更改为 1 时,下一个对象会呈现。但我不能让它与按钮一起工作。当我单击按钮时,它会直接跳转到警报消息。

function GetMovies() {
  useEffect(() => {
    fetchItems();
  }, []);

  const [items, setItems] = useState({ options: [] });

  const fetchItems = async () => {
    const data = await fetch("http://localhost:5000/api/movies");
    const items = await data.json();
    //test
    //console.log(items[currentQuestion]);
    setItems(items[currentQuestion]);
  };

  
  const [currentQuestion, setCurrentQuestion] = useState(0);

  //change question solution that dont work
  const HandleAnswerButtonClick = () => {
    const nextQuestion = setCurrentQuestion + 1;
    if (nextQuestion < items.length) {
      setCurrentQuestion(nextQuestion);
    } else {
      alert("End of quiz");
    }
    setCurrentQuestion(nextQuestion);
  };

  return (
    <div className="App">
      <h1>Quiza</h1>
      <div>
        <span>Question 1</span>
      </div>
      <div>
        <h3>Question: {items.description}</h3>
        {items.options.map((c) => (
          <button value={c.is_correct} key={c.text}>
            {c.text}
          </button>
        ))}
        <div>
        {//Next BUTTON}
          <button onClick={() => HandleAnswerButtonClick()}>
            Next question
          </button>
        </div>
        {/* if-sats, om bild finns till frågan visas den, annars en class med display none */}
        <div className="Q_pics">
          {items.options.map((c) =>
            !c.image ? (
              <p className="Display_none">empty</p>
            ) : (
              <img src={c.image} alt={c.text}></img>
            )
          )}
        </div>
      </div>
    </div>
  );
}

我的 API 中的猫鼬模式

const MovieSchema = mongoose.Schema(
  {
    category: { type: String, required: true },
    description: { type: String, required: true },
    image: {
      type: String,
      required: false,
    },
    options: [
      {
        text: {
          type: String,
          required: true,
        },
        is_correct: {
          type: Boolean,
          required: true,
          default: false,
        },
        image: {
          type: String,
          required: false,
        },
      },
    ],
  },
  { collection: "movies" }
); 

【问题讨论】:

  • 您应该将 items 设置为您从端点返回的电影对象数组,以便您可以更改显示的项目。目前,您似乎将其设置为特定的电影对象,因此它没有 .length 属性,这意味着您下次更改问题时需要再次向端点询问项目数组.调试提示是记录您的变量。如果您的 if 语句有问题,您可以使用 console.log(nextQuestion, items.length) 查看您的 if 语句正在检查什么

标签: javascript arrays reactjs api use-state


【解决方案1】:

那是因为

const nextQuestion = setCurrentQuestion + 1;

应该是

const nextQuestion = currentQuestion + 1;

哦,正如@Nick Parsons 在评论中提到的那样,您也只将第一个问题存储在您的状态中,因为fetchItems 只运行一次,而您执行setItems(items[currentQuestion]);

你应该做类似的事情

function GetMovies() {
  const [items, setItems] = useState([]);    
  const [currentQuestion, setCurrentQuestion] = useState(0);

  const fetchItems = async () => {
    const data = await fetch("http://localhost:5000/api/movies");
    const items = await data.json();
    //test
    //console.log(items[currentQuestion]);
    setItems(items);
  };
  
  //change question solution that dont work
  const HandleAnswerButtonClick = () => {
    const nextQuestion = currentQuestion + 1;
    if (nextQuestion < items.length) {
      setCurrentQuestion(nextQuestion);
    } else {
      alert("End of quiz");
    }
    setCurrentQuestion(nextQuestion);
  };

  useEffect(() => {
    fetchItems();
  }, []);

  const activeQuestion = items[currentQuestion];
  
  return (
    <div className="App">
      <h1>Quiza</h1>
      <div>
        <span>Question {currentQuestion + 1}</span>
      </div>
      <div>
        <h3>Question: {activeQuestion && activeQuestion.description}</h3>
        {activeQuestion && activeQuestion.options.map((c) => (
          <button value={c.is_correct} key={c.text}>
            {c.text}
          </button>
        ))}
        <div>
        {//Next BUTTON}
          <button onClick={() => HandleAnswerButtonClick()}>
            Next question
          </button>
        </div>
        {/* if-sats, om bild finns till frågan visas den, annars en class med display none */}
        <div className="Q_pics">
          {activeQuestion && activeQuestion.options.map((c) =>
            !c.image ? (
              <p className="Display_none">empty</p>
            ) : (
              <img src={c.image} alt={c.text}></img>
            )
          )}
        </div>
      </div>
    </div>
  );
}

【讨论】:

  • 谢谢,但它仍然会直接跳到警报消息
  • @Haddock 查看尼克对您问题的评论
  • 好吧,这似乎可行,但在刷新页面时,我得到一个空白页面,控制台显示“未捕获的 TypeError:activeQuestion 未定义”。上次发生这种情况时,我使用了“const [item, setItem] = useState({ options: [] });”但这一次不会成功。删除“

    {activeQuestion.description}

    ”时,它工作正常。
  • @Haddock 是的。 {activeQuestion.description} 也应该有像 {activeQuestion &amp;&amp; activeQuestion.description} 这样的守卫。但是如果activeQuestionundefined,你可能想要return null,这样你就不必在每个地方都守卫。
【解决方案2】:

代码可能是这样的:

  const [items, setItems] = useState({ options: [] });
    // currentIdx might be a better name
  const [currentIdx, setCurrentIdx] = useState(0);
  const fetchItems = async () => {
    const data = await fetch("http://localhost:5000/api/movies");
    const items = await data.json();
        //  save all data as Nick said. and items should be type of Data[];
    setItems(items);
  };
  const HandleAnswerButtonClick = () => {
    const nextQuestion = currentIdx + 1;
    if (nextQuestion < items.length) {
      setCurrentIdx(nextQuestion);
    } else {
      alert("End of quiz");
    }
  };
    // use displayItem for render 
  const displayItem = useMemo(() => items[currentIdx], [items, currentIdx]);

我认为你最好学习使用开发工具并观察代码的价值?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-01-15
    • 1970-01-01
    • 2021-03-17
    • 1970-01-01
    • 2020-08-31
    • 2015-05-06
    • 2021-02-13
    • 1970-01-01
    相关资源
    最近更新 更多