【问题标题】:for loops in reacts js反应js中的for循环
【发布时间】:2019-06-22 19:59:03
【问题描述】:

我正在尝试更新这些值,但无论何时我console.log 总是0,即使条件为真。

import React, { Component } from "react";

interface orderInformation {
  customer: number;
  picklePrice: number;
  breadPrice: number;
}

interface ComponentState {
  customer: number;
  picklePrice: number;
  breadPrice: number;
  error: string;
  finalPickleCost: number;
  finalBreadCost: number;
  pickleCounter: number;
  breadCounter: number;
}

export default class pickleSandwich extends Component<
  orderInformation,
  ComponentState
> {
  constructor(props: orderInformation) {
    super(props);

    //initializing variables to undefined
    this.state = {
      customer: 0,
      picklePrice: 0,
      breadPrice: 0,
      finalBreadCost: 0,
      finalPickleCost: 0,
      pickleCounter: 0,
      breadCounter: 0,
      error: ""
    };
    this.handleChange = this.handleChange.bind(this);
  }

  //Get information for the user
  getInfo = orderInformation => {
    orderInformation.preventDefault();

    const { customer, picklePrice, breadPrice } = this.state;
    console.log("customer", customer);
    console.log("pickle", picklePrice);
    console.log("bread", breadPrice);
    if (customer > 0) {
      for (var i = 0; i < customer; i++) {
        if (i % 3 === 0) {
          this.setState({
            pickleCounter: this.state.pickleCounter + 2,
            breadCounter: this.state.breadCounter + 3
          });
        } else {
          this.setState({
            pickleCounter: this.state.pickleCounter + 1,
            breadCounter: this.state.breadCounter + 2
          });
        }
      }
    } else {
      this.setState({
        error: "Please enter amount of customer"
      });
    }
    console.log("pickle Counter", this.state.pickleCounter);
    console.log("breadCounter", this.state.breadCounter);
  };

  handleChange = e => {
    this.setState({ [e.target.name]: e.target.value } as any);
  };

  render() {
    // const { customer, finalPickleCost, finalBreadCost } = this.state;

    return (
      <form onSubmit={this.getInfo}>
        <p>Get the information of the order!</p>
        <input
          type="text"
          id="customer"
          value={this.state.customer}
          placeholder="Amount of Customers"
          name="customer"
          onChange={this.handleChange}
          required
        />
        <input
          type="text"
          id="picklePrice"
          placeholder="Price of Pickle"
          value={this.state.picklePrice}
          name="picklePrice"
          onChange={this.handleChange}
          required
        />

        <input
          type="text"
          id="breadBrice"
          placeholder="Price of Bread"
          value={this.state.breadPrice}
          name="breadPrice"
          onChange={this.handleChange}
          required
        />
        <button type="submit" onClick={this.getInfo}>
          Get Information{" "}
        </button>
      </form>
    );
  }
}

我希望它更新值,以便计算最终成本。

【问题讨论】:

    标签: reactjs


    【解决方案1】:

    React 的 setState 是异步的,这意味着当你到达 console.log 时,状态可能还没有更新。

    有关此行为的更多信息,请参阅 thisthis 以及一般情况下的 setState

    为了规避这个问题,您可以使用setState 的回调方法,一旦执行状态更新就会触发该方法:

    this.setState(prevState => ({
        pickleCounter: prevState.pickleCounter + 1,
        breadCounter: prevState.breadCounter + 2
    }), () => {
        // once you're here the state updated successfully
    });
    

    【讨论】:

    • 你知道,我比我更喜欢这个答案。出于某种原因,我从未想过将 async/await 用于 setState。
    • @ChrisSandvik 没关系,this.setState 没有 returnPromise 所以你不能 await 为它。
    • @AsafAviv 你是对的。我不得不阅读这个主题并且感到困惑。我 100% 确定您可以等待 setState。感谢您指出这一点,一旦我周一回到工作岗位,我将不得不改变一些事情。 你知道的越多
    • @ChrisSandvik 每个文档的第一部分不应该工作,所以我删除了它。继续使用回调就可以了!
    • @ChrisSandvik 如果函数返回Promiseawait,则只能为函数await 创建一个滴答延迟。
    【解决方案2】:

    你可以像这样更新值

    if(i%3 === 0)
    {
      this.setState((prevState)=>{
        return {
          pickleCounter: prevState.pickleCounter + 2,
          breadCounter:  prevState.breadCounter + 3
        }
    
      });
    }
    

    在这里,在this.setState() 内部,我们不仅提供了新状态,还提供了返回新状态的函数,通过这种方式,我们可以访问旧状态。您可以选择任何变量名称而不是 prevState 来表示之前的状态。

    【讨论】:

    • 这仍然有效,值没有更新。
    • 您在更新客户数量吗?检查您有多少客户可能会发现错误。
    【解决方案3】:

    设置状态是一个异步函数,因此如果在同一个函数中调用新状态通常是不可访问的,除非您为setState 函数使用回调:

    this.setState({...content...}, callbackFunction)
    

    编辑

    使用 Tobias 最初提到的但并没有像他描述的那样起作用的东西给了我一个想法。在这种情况下使用 async await 的一种方法是添加一个自定义函数以使 setState 返回一个 Promise。

    setStateAsync(state) {
        return new Promise((resolve) => {
          this.setState(state, resolve)
        });
    }
    

    你可以使用它来让你的函数等待状态被设置。

    setStateAsync(state) {
      return new Promise((resolve) => {
        this.setState(state, resolve)
      });
    }
    
    //Get information for the user
    getInfo = async orderInformation => {
      orderInformation.preventDefault();
    
      const {
        customer,
        picklePrice,
        breadPrice
      } = this.state;
      console.log("customer", customer);
      console.log("pickle", picklePrice);
      console.log("bread", breadPrice);
      if (customer > 0) {
        for (var i = 0; i < customer; i++) {
          if (i % 3 === 0) {
            await this.setStateAsync({
              pickleCounter: this.state.pickleCounter + 2,
              breadCounter: this.state.breadCounter + 3
            });
          } else {
            await this.setStateAsync({
              pickleCounter: this.state.pickleCounter + 1,
              breadCounter: this.state.breadCounter + 2
            });
          }
        }
    
    
      } else {
        await this.setStateAsync({
          error: "Please enter amount of customer"
        });
      };
      console.log("pickle Counter", this.state.pickleCounter);
      console.log("breadCounter", this.state.breadCounter);
    };
    

    【讨论】:

    • 我目前正在学习 React,我正在做这个练习,你介意快速解释一下 callbackFunction 以及如何使用它吗?
    • 回调函数就是你想要在设置状态后运行的任何函数。因此,在您的情况下,它可能不是正确的解决方案,因为您的输出取决于大小写。您能否发布更长的代码块,以便我了解您如何尝试使用它?
    • 将其添加为答案
    • @DanielIsaacChavez 检查我更新的答案,我相信这是解决您问题的最简单方法
    • 您的编辑肯定很有趣,但对我来说太老套了。 ^^
    【解决方案4】:

    React setState() 可能是异步的,这意味着更新一个值并在之后安慰它可能会给你旧数据,这样做是错误的

    // wrong, anti-pattern
    this.setState({
      pickleCounter: this.state.pickleCounter + 2,
      breadCounter: this.state.breadCounter + 3
    });
    

    更好的方法

    setState(updater[, callback])

    //  good
    this.setState((prevState) => {
      return { 
        pickleCounter: prevState.pickleCounter + 2,
        breadCounter: prevState.breadCounter + 3
      }
    });
    

    工作示例

    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.0/umd/react.production.min.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.0/umd/react-dom.production.min.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.21.1/babel.min.js"></script>
    
    <div id="root"></div>
    
    <script type="text/babel">
    
    class App extends React.Component {
      //initializing variables to undefined
      state = {
        customer: 0,
        picklePrice: 0,
        breadPrice: 0,
        finalBreadCost: 0,
        finalPickleCost: 0,
        pickleCounter: 0,
        breadCounter: 0,
        error: ""
      };
    
      handleChange = e => {
        this.setState({ [e.target.name]: e.target.value }
        );
      };
    
      //Get information for the user
        getInfo = async (orderInformation) => {
        orderInformation.preventDefault();
    
        const { customer, picklePrice, breadPrice } = this.state;
        console.log("customer", customer);
        console.log("pickle", picklePrice);
        console.log("bread", breadPrice);
        if (customer > 0) {
          for (var i = 0; i < customer; i++) {
            if (i % 3 === 0) {
              await this.setState((prevState) => {
                return {
                  pickleCounter: prevState.pickleCounter + 2,
                  breadCounter: prevState.breadCounter + 3
                }
              }, () => {
                console.log("pickle Counter", this.state.pickleCounter);
                console.log("breadCounter", this.state.breadCounter);
              });
            }
            else {
             await this.setState((prevState) => {
                return {
                  pickleCounter: prevState.pickleCounter + 1,
                  breadCounter: prevState.breadCounter + 2
                }
              }, () => {
                console.log("pickle Counter", this.state.pickleCounter);
                console.log("breadCounter", this.state.breadCounter);
              });
            }
          }
    
    
        } else {
          this.setState({
            error: "Please enter amount of customer"
          });
        };
      };
      
      render() {
        // const { customer, finalPickleCost, finalBreadCost } = this.state;
    
        return (
          <form onSubmit={this.getInfo}>
            <p>Get the information of the order!</p>
            <input
              type="text"
              id="customer"
              value={this.state.customer}
              placeholder="Amount of Customers"
              name="customer"
              onChange={this.handleChange}
              required
            />
            <input
              type="text"
              id="picklePrice"
              placeholder="Price of Pickle"
              value={this.state.picklePrice}
              name="picklePrice"
              onChange={this.handleChange}
              required
            />
    
            <input
              type="text"
              id="breadBrice"
              placeholder="Price of Bread"
              value={this.state.breadPrice}
              name="breadPrice"
              onChange={this.handleChange}
              required
            />
            <button type="submit" onClick={this.getInfo}>Get Information </button>
    
          </form>
        );
      }
    }
    
    ReactDOM.render(<App />, document.getElementById("root"));
    </script>

    您可以将回调传递给setState,该回调将在 setState 完成设置状态后调用。

    this.setState((prevState) => {
      pickleCounter: prevState.pickleCounter + 2,
      breadCounter: prevState.breadCounter + 3
    }, () => {
      // code here
    });
    

    或者使用异步/等待

    await this.setState({...})
    

    异步/等待示例

    没有 async/await,状态可能是异步的。

    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.0/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.0/umd/react-dom.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.21.1/babel.min.js"></script>
    
    <div id="root"></div>
    
    <script type="text/babel">
    
    class App extends React.Component {
    
      state = {
        name: 'React'
      };
    
    
      componentDidMount = () => {
    
        this.setState({
          name: 'Peter'
        });
    
        console.log('logs old value: ', this.state.name);
      }
    
      render() {
        return (
          <div>
            <p>{this.state.name}</p>
          </div>
        );
      }
    }
    
    ReactDOM.render(<App />, document.getElementById("root"));
    </script>

    使用异步/等待

    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.0/umd/react.production.min.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.0/umd/react-dom.production.min.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.21.1/babel.min.js"></script>
    
        <div id="root"></div>
    
        <script type="text/babel">
    
        class App extends React.Component {
    
          state = {
            name: 'React'
          };
    
    
          componentDidMount = async () => {
    
            await this.setState({
              name: 'Peter'
            });
    
            console.log('logs new value: ', this.state.name);
          }
    
          render() {
            return (
              <div>
                <p>{this.state.name}</p>
              </div>
            );
          }
        }
    
        ReactDOM.render(<App />, document.getElementById("root"));
        </script>

    请参阅以下文档。

    State Updates May Be Asynchronous

    setState

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-10-18
      • 1970-01-01
      • 2019-04-24
      • 1970-01-01
      • 1970-01-01
      • 2021-12-03
      • 2015-08-28
      • 1970-01-01
      相关资源
      最近更新 更多