this.setState 不起作用(我的状态是一个数字)

Posted

技术标签:

【中文标题】this.setState 不起作用(我的状态是一个数字)【英文标题】:this.setState isn't working (my state is a number) 【发布时间】:2019-01-03 06:31:35 【问题描述】:

我遇到了问题:this.setState(score: counter);由于某种原因,它没有更新。为什么?即使我这样做了 this.setState(score: 5) 或 score:"a string" 它仍然不起作用。我错过了什么吗?无论我做什么,状态都不会改变。我必须添加额外的描述,因为网站不允许我发布我的问题。

displayResultsHandler = () => 
    var counter = 0;
    for(let i = 0; i < this.state.correctAnswers.length; i++) 
      if(this.state.correctAnswers[i] === this.state.userAnswers[i]) 
        counter = counter+1;
      
    

this.setState(
  score: counter
);

console.log("counter: " + counter);
console.log("score: " + this.state.score); // For some reason, this is always zero

我在下面添加了我的完整代码。也许会有所帮助。

import React,  Component  from 'react';
import './App.css';
import Title from './Title/Title';
import Question from './Question/Question';
import Aux from './hoc/Aux';
import SubmitButton from './SubmitButton/SubmitButton';

class App extends Component 
  state = 
    questionArray: [
      "What is 9+10",
      "How many goals did Ronaldo score against Spain in the World Cup 2018",
      "Who Stole Ronaldo's (CR7) greates ever goal?",
      "Which one of these players ruined the NBA",
      "Who is currently number 1 in the internet L rankings?"
  ],
    answerChoicesArray: [
      ["1", "19", "21", "90", "-1"],
      ["1", "3", "5", "0", "-1"],
      ["Pepe", "Messi", "Casillas", "Benzema", "Nani"],
      ["Allen Iverson", "Kevin Durant", "Steph Curry", "Lebron James", "Russel West***"],
      ["Drake", "Pusha T", "Russel West***", "Lil Xan", "Russ"]
    ],

    correctAnswers: ["21", "3", "Nani", "Kevin Durant", "Russ"],

    userAnswers: ["", "", "", "", ""],

    score: 0

  

  updateUserAnswersHandler = (oldArray, index, value) => 
    const newArray = oldArray;
    newArray[index] = value;
    this.setState(
      userAnswers: newArray
    );
  

  displayResultsHandler = () => 
    var counter = 0;
    for(let i = 0; i < this.state.correctAnswers.length; i++) 
      if(this.state.correctAnswers[i] === this.state.userAnswers[i]) 
        counter = counter+1;
      
    

    this.setState(
      score: counter
    );

    console.log("counter: " + counter);
    console.log("score: " + this.state.score); // For some reason, this is always zero

    if(this.state.score < 5) 
      alert("You're dumb asf. Please leave");
     else 
      alert("Welcome to NASA");
    
  

  render() 
    // var userAnswers;
    // console.log(userAnswers); How do I pass this as a prop? this.userAnswers? nope. Therefore it has to be a state
    console.log("User Answers are: " + this.state.userAnswers);
    return (
      <div className="App">
        <div className="container">
          
            <Title/>
            <h2>Only the most genius of individuals will pass</h2>
            <hr/>
            <Question
              correctAnswers=this.state.correctAnswers
              updateUserAnswersHandler=this.updateUserAnswersHandler
              userAnswers=this.state.userAnswers
              questionArray=this.state.questionArray
              answerChoicesArray=this.state.answerChoicesArray />
            <SubmitButton
              clicked = this.displayResultsHandler />
        </div>
      </div>
    );
  


export default App;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

【问题讨论】:

你在类中添加了构造函数吗? 没有。我以为我们不需要最新版本的构造函数?因为我能够在没有构造函数的情况下更改我的 userAnswers 状态 【参考方案1】:

状态更新是异步的。您对setState 的调用只是将更新排队,不会立即发生。

您还使用了错误的 setState 重载(您并不孤单,很多人都这样做!)。当您根据现有状态设置新状态时,您不能使用只接受对象的版本。您必须使用回调版本。如果您想在完成后使用结果状态,您可以传递第二个函数,该函数将在状态更新完成时调用:

displayResultsHandler = () => 
    this.setState(
        // Updater
        prevState => 
            var counter = 0;
            for(let i = 0; i < prevState.correctAnswers.length; i++) 
              if(prevState.correctAnswers[i] === prevState.userAnswers[i]) 
                counter = counter+1;
              
            
            return score: counter;
        ,
        // Completion callback
        () => 
            console.log("score: " + this.state.score);
        
    );
;

但是,文档说明了使用完成回调:

一般我们建议使用componentDidUpdate() 来代替这种逻辑。

这在文档的this page 和setState API docs 中都有介绍。


顺便说一句,一些高级 javascript 功能(解构和速记属性表示法)和一个平淡无奇的功能(增量运算符)可以使代码更加简洁:

displayResultsHandler = () => 
    this.setState(
        // Updater
        (correctAnswers, userAnswers) =>                   // *** Destructuring
            let score = 0;
            for (let i = 0; i < correctAnswers.length; i++) 
              if (correctAnswers[i] === userAnswers[i]) 
                ++score;                                      // *** Increment
              
            
            return score;                                   // *** Shorthand property
        ,
        // Completion callback
        () => 
            console.log("score: " + this.state.score);
        
    );
;

有些人甚至可能使用reduce 而不是for 循环;不过,我不相信可读性不会受到影响:

displayResultsHandler = () => 
    this.setState(
        // Updater
        (correctAnswers, userAnswers) => (
            score: correctAnswers.reduce(
                (score, answer, index) =>
                    score + (answer === userAnswers[index] ? 1 : 0),
                0
            )
        ),
        // Completion callback
        () => 
            console.log("score: " + this.state.score);
        
    );
;

(你甚至可以放弃条件运算符,只使用score + (answer === userAnswers[index]),因为true 强制转换为1false 强制转换为0,但是...)

【讨论】:

这就是我要找的。谢谢! 所以我明白你在说什么。但是我没有根据现有状态使用setState。我做了setState(score: counter),那是怎么基于现有状态的呢?我是否还需要更新此处理程序以修改 userAnswers 数组? updateUserAnswersHandler = (oldArray, index, value) => const newArray = oldArray;新数组[索引] = 值; this.setState( userAnswers: newArray ); “我做了setState(score: counter),那是怎么基于现有状态的?” 那个counter值是从哪里来的? :-) 是的,其他处理程序也需要修复,更多信息在这里:***.com/a/51524337/157247 @user7552492 - 再看一遍,关于updateUserAnswersHandler 处理程序的问题的答案取决于oldArray 的来源。但是,是的,它可能有同样的问题。 是的。如果您查看我发送的较长的代码,我会两次将我的 userAnswers 状态作为道具传递给我的 Question 组件,如下所示:userAnswers=this.state.userAnswers。两个文件下来,我这样调用 updateUsersHandler:this.props.updateUserAnswersHandler(this.props.userAnswers, this.props.index, individualAnswer);。我很确定我必须解决这个问题,因为它使用的是旧状态(this.props.userAnswers),但我不知道该怎么做。谢谢【参考方案2】:

this.setState 是一个异步函数。

试试这个 -

this.setState(
  score: counter
,function()
  console.log(this.state.score)
)

【讨论】:

不行,OP必须使用updater回调,不能直接传入对象,因为这是基于状态的状态更新。 该方法打印出正确的状态,但状态本身仍然为零

以上是关于this.setState 不起作用(我的状态是一个数字)的主要内容,如果未能解决你的问题,请参考以下文章

React Stateful Class Component:使用“this.setState”更新状态的属性,不起作用。没有错误。状态不变

React setState 在第一次尝试时不起作用,但在第二次尝试时起作用?

在 React 中使用数组设置状态

如何取消 `this.setState`?

TypeError:未定义不是对象(评估'this.setState')[重复]

如何在我的示例中正确使用 setState()?