一级延迟反应父组件复选框状态更新

时间:2018-10-23 18:37:32

标签: reactjs

我有一个上级组件:

Sub Concatenate()

' Concatenate two columns
Dim l As Long, lRow As Long
With ActiveSheet
    lRow = .Range("A" & Rows.Count).End(xlUp).Row
    For l = 2 To lRow
        ActiveSheet.Cells(l, 3) = .Cells(l, 1) & " " & .Cells(l, 2)
    Next l
End With

End Sub

...和一个子组件:

import React, { Component } from "react";
import { Button } from "./Button";

export class Dashboard extends Component {
  constructor(props) {
    super(props);
    this.state = {
      numbers: [],
      disabled: false
    };

    this.setNum = this.setNum.bind(this);
  }

  setNum(num) {
    if (!this.state.numbers.includes(num)) {
      this.setState(prevState => ({
        numbers: [...prevState.numbers, num]
      }));
    } else if (this.state.numbers.includes(num)) {
      let nums = [...this.state.numbers];
      let index = nums.indexOf(num);
      nums.splice(index, 1);
      this.setState({ numbers: nums });
      console.log(this.state.numbers);
    }
    if (this.state.numbers.length >= 4) {
      this.setState({ disabled: true });
    } else if (this.state.numbers.length < 4) {
      this.setState({ disabled: false });
    }
  }

  render() {
    return (
      <div className="board-container">
        <div className="board">
          <div className="row">
            <Button
              id="1"
              numbers={this.state.numbers}
              onChange={this.setNum}
              disabled={this.state.disabled}
            />
            <Button
              id="2"
              numbers={this.state.numbers}
              onChange={this.setNum}
              disabled={this.state.disabled}
            />
            <Button
              id="3"
              numbers={this.state.numbers}
              onChange={this.setNum}
              disabled={this.state.disabled}
            />
            <Button
              id="4"
              numbers={this.state.numbers}
              onChange={this.setNum}
              disabled={this.state.disabled}
            />
          </div>
        </div>
      </div>
    );
  }
}

每当单击任何Button组件时,Parent组件都会获取子Button的import React, { Component } from "react"; export class Button extends Component { constructor(props) { super(props); this.state = { isChecked: false }; this.handleChange = this.handleChange.bind(this); } handleChange(e) { this.setState({ isChecked: !this.state.isChecked }); var num = e.target.value; this.props.onChange(num); } render() { const { isChecked } = this.state; if (isChecked === true) { var bgColor = "#f2355b"; } else { bgColor = "#f7f7f7"; } let disabled = this.props.disabled; if (this.props.numbers.includes(this.props.id)) { disabled = false; } return ( <div className="number-container" id="checkboxes"> <label className={!isChecked && disabled === false ? "num" : "checked-num"} style={{ backgroundColor: bgColor }} > {" "} {this.props.id} <input type="checkbox" name={this.props.id} value={this.props.id} id={this.props.id} onChange={this.handleChange} checked={isChecked} disabled={disabled} /> </label> </div> ); } } 值并将其放入其id状态数组。每当取消选中一个Button时,通过删除子Button的numbers,Parent更新处于numbers状态。

如果我的代码正确,则预期的行为是每当单击id复选框时,“父编号”状态将立即更新(添加或删除数字)。但是,它总是在更新时落后一步。

我知道,该问题正在处理无法立即更新的React状态,我已经检查了Stackoverflow上的类似问题。问题是我无法弄清楚如何使这两个组件以适当的方式相互交互。该问题的解决方案是什么?

2 个答案:

答案 0 :(得分:2)

enter image description here

enter image description here

enter image description here

这是来自codeandbox的三个屏幕截图

如果要使用它,请找到链接https://codesandbox.io/s/w2q8ypnxjw

我所做的是,我基本上复制并粘贴了您的代码,并更新了setNum函数以反映Think-Twice建议的更改

  setNum(num) {
    if (!this.state.numbers.includes(num)) {
      this.setState(
        prevState => ({
          numbers: [...prevState.numbers, num]
        }),
        () => {
          console.log("state logged inside if", this.state.numbers);
        }
      );
    } else if (this.state.numbers.includes(num)) {
      let nums = [...this.state.numbers];
      let index = nums.indexOf(num);
      nums.splice(index, 1);
      this.setState({ numbers: nums }, () => {
        console.log("state logged inside else if", this.state.numbers);
      });
    }
    if (this.state.numbers.length >= 4) {
      this.setState({ disabled: true });
    } else if (this.state.numbers.length < 4) {
      this.setState({ disabled: false });
    }
  }

因此,在进一步介绍之前,让我们快速解决与React和setState有关的几件事

  1. B12Toaster所述,并提供了一个包含 官方文件中的报价

      

    setState()并不总是立即更新组件。它可能   批量更新或将更新推迟到以后。

    Think-Twice也指出了

      

    基本上setState在React中是异步的。修改值时   使用setState您将只能在以下位置查看更新的值   渲染。

    因此,如果您想查看某个地方的即时状态变化, 您触发setState时,可以将回调函数用作 这样的setState(updater[, callback])

  2. 使用setState和updater时有两种方法, 您可以传递一个对象,也可以传递一个函数 以两次思考为例,对象作为更新程序传递

    this.setState({ numbers: nums } //updater, () => {
            console.log(this.state.numbers); //this will print the updated value here
      });
    

    将一个函数用作更新程序时(在setNum函数中, 已经做到了),则可以像下面那样利用回调函数

    if (!this.state.numbers.includes(num)) {
          this.setState(
            prevState => ({
              numbers: [...prevState.numbers, num]
            }),
            () => {
              console.log("state logged inside if", this.state.numbers);
            }
          );
        }
    

您当前的实现和通信结构看起来还不错。它实际上称为Lifting State Up,官方文档也建议使用此名称。 基本上,您将数组编号的状态存储在父组件中(可以将其视为事实的来源),然后将更改状态的方法作为对其子组件的支持。

在我提供的codesandbox链接中,功能按我期望的方式运行(至少这是我对您的代码的期望)

答案 1 :(得分:1)

基本上setState在React中是异步的。使用setState修改值时,您将只能在render中看到更新后的值。但是要立即查看更新的状态值,您需要执行以下操作

  this.setState({ numbers: nums }, () => {
        console.log(this.state.numbers); //this will print the updated value here
  });