【问题标题】:React state updating but not showing while render反应状态更新但渲染时不显示
【发布时间】:2022-01-05 19:15:32
【问题描述】:

我正在研究react,我已经制作了一个表格来保存react数据, 我想在保存数据时再次更新表格,为此我使用了 setState,问题是状态更新而不是渲染,我尝试了一些方法来找到问题,

  1. 使用console.log()发现状态变化正常
  2. 改变状态后渲染功能正常工作

这是我的代码

import React, { Component } from "react";
import Header from "../header";
import Table from "./table";
import Addbox from "./create__box";
import $ from "jquery";
import { Api__url } from "../../vars";

class index extends Component {
  constructor(props) {
    super(props);
    // binding functions
    this.getData = this.getData.bind(this);
    this.table = this.table.bind(this);
    this.show_create_box = this.show_create_box.bind(this);
    // using state
    this.state = {
      data: "Fetching Records....",
      create_box: "",
    };
  }

  getData() {
    $.ajax({
      type: "POST",
      url: `${Api__url}services/get`,
      dataType: "JSON",
      success: this.table,
    });
  }

  table(d) {
    this.setState({ data: <Table data={d} /> });
  }

  show_create_box() {
    this.setState({create_box: <Addbox top="15vh" again_get_data={this.getData}/>});
  }

  componentDidMount() {
    this.getData();
  }

  render() {
    return (
      <>
        <Header />
        <div className="container mt-5 px-5">
          <div className="border__box p-2 col">
            <div className="row m-0 px-3">
              <div className="col">
                <h2>Services in home page</h2>
              </div>
              <div className="col d-flex justify-content-end">
                <button
                  onClick={this.show_create_box}
                  className="btn btn-outline-success show__create__box"
                >
                  Add New Data
                </button>
              </div>
            </div>
            <div className="row m-0 py-2 px-4">{this.state.data}</div>
          </div>
        </div>
        {this.state.create_box}
      </>
    );
  }
}

export default index;

```

the code from the table file
```
import React, { Component } from "react";
import Updatebox from "./update__box";

class table extends Component {
  constructor(props) {
    super(props);
    this.show_update_box = this.show_update_box.bind(this);
    this.delete_record = this.delete_record.bind(this);
    this.state = { update_box: "" };

    // making data
    this.tbody = props.data.map((d, index) => {
      return (
        <tr className="w-100 row m-0 p-0" id={d.services_id}>
          <th className="col-1" scope="row">
            {index + 1}
          </th>
          <td className="col-3">{d.services_name}</td>
          <td className="col-4">{d.services_description}</td>
          <td className="col-2">{d.services_icon}</td>
          <td className="col-1">
            <button
              onClick={() => {
                this.show_update_box(index);
              }}
              className="btn btn-outline-success"
            >
              Update
            </button>
          </td>
          <td className="col-1">
            <button
              onClick={() => {
                this.delete_record(index);
              }}
              className="btn btn-outline-danger"
            >
              Delete
            </button>
          </td>
        </tr>
      );
    });
  }

  // Function to get close form instruction from another class
  changeStuff(d) {
    this.setState(d);
  }

  delete_record(id) {
    alert(id);
  }

  show_update_box(key) {
    this.setState({
      update_box: (
        <Updatebox
          data={this.props.data[key]}
          changeHandler={this.changeStuff.bind(this)}
        />
      ),
    });
  }

  render() {
    return (
      <>
        <table className="position-relative table table-hover ">
          <thead className="table-dark">
            <tr className="row m-0 p-0">
              <th className="col-1">Sr #</th>
              <th className="col-3">Name</th>
              <th className="col-4">Description</th>
              <th className="col-2">Icon</th>
              <th className="col-1">Update</th>
              <th className="col-1">Delete</th>
            </tr>
          </thead>
          <tbody>{this.tbody}</tbody>
        </table>
        {this.state.update_box}
      </>
    );
  }
}

export default table;

```

here's the code for creating the box
```
import React, { Component } from "react";
import CloseIcon from "@mui/icons-material/Close";
import $ from "jquery";
// import i from "./index";

export default class Addbox extends Component {
  constructor(props) {
    super(props);
    this.data = { name: "", description: "", icon: "" };
    this.state = this.data;
    this.change = this.change.bind(this);
    this.submit = this.submit.bind(this);
    this.changeCSS = this.changeCSS.bind(this);
    this.setCSS = this.setCSS.bind(this);
    this.close_create_box = this.close_create_box.bind(this);
  }

  close_create_box() {
    this.props.changeHandler({ create_box: "" });
  }

  change(e) {
    var name = e.target.name;
    var value = e.target.value;
    this.setState({
      [name]: value,
    });
  }

  changeCSS() {
    $("#create").removeClass("btn-outline-success");
    $("#create").addClass("btn-outline-dark");
    $("#create").prop("disabled", true);
    $("#create").text("Sending....");
  }

  setCSS() {
    $("#create").removeClass("btn-outline-dark");
    $("#create").addClass("btn-outline-success");
    $("#create").prop("disabled", false);
    $("#create").text("Submit");
  }

  submit(e) {
    e.preventDefault();
    $.ajax({
      type: "POST",
      url: "http://127.0.0.1:8000/api/services/create",
      data: this.state,
      dataType: "JSON",
      beforeSend: this.changeCSS,
      success: (e) => {
        alert(e.message);
        this.props.again_get_data();
        this.close_create_box();
      },
      error: (e) => {
        this.setCSS();
        alert(e.responseText);
      },
    });
  }

  render() {
    return (
      <form
        onSubmit={this.submit}
        className="add__box create__box"
        method="POST"
        style={{ top: this.props.top }}
      >
        <div className="mb-3 row">
          <div className="col-10">
            <h4>Add New Service</h4>
          </div>
          <div className="col-2">
            <CloseIcon className="close" onClick={this.close_create_box} />
          </div>
        </div>
        <div className="mb-3">
          <label htmlFor="create_name" className="form-label">
            Name
          </label>
          <input
            id="create_name"
            name="name"
            type="text"
            className="form-control"
            onChange={this.change}
            value={this.state.name}
            required
            minLength={10}
            maxLength={100}
          />
        </div>
        <div className="mb-3">
          <label htmlFor="create_desc" className="form-label">
            Description
          </label>
          <textarea
            id="create_desc"
            className="form-control"
            onChange={this.change}
            required
            value={this.state.description}
            minLength={20}
            name="description"
          ></textarea>
        </div>
        <div className="mb-3">
          <label htmlFor="create_icon" className="form-label">
            Icon
          </label>
          <input
            id="create_icon"
            type="text"
            className="form-control"
            onChange={this.change}
            value={this.state.icon}
            required
            name="icon"
          />
        </div>
        <div className="m-5 row my-0">
          <button id="create" type="submit" className="btn btn-outline-success">
            Submit
          </button>
        </div>
      </form>
    );
  }
}

```

【问题讨论】:

    标签: reactjs react-native web-deployment use-state setstate


    【解决方案1】:

    根据react docs,UI 组件不应处于状态,它应仅包含表示 UI 状态所需的最少量数据。

    因此,与其在状态中添加 UI 元素,不如在其中添加最少量的数据

    这是一个基于您的代码的示例

    constructor(props) {
       ...
       this.state = {
         status: "loading",
         data: "Fetching Records....",
         create_box: "",
       };
    }
    
    table(d) {
      this.setState({ data: d, status: "table" });
    }
    
    renderData() {
       const d = this.state.data
       const status = this.state.status
       if (status == "loading") { return d }
       if (status == "table") { return <Table data={d} /> }
    }
    
    render() {
        return (
          <>
            ...
            <div className="row m-0 py-2 px-4">{renderData()}</div>
            ...
          </>
        );
    }
    

    【讨论】:

    • 我试过了,但是函数在新数据到达之前渲染记录,如何延迟??
    • @UsamaJaved 如果你还没有调用setState 函数,渲染时将显示的数据是状态的初始数据,在这种情况下是"Fetching Records...."
    • 我明白了,但是我想问一下我什么时候创建一个新记录并再次调用getData(),它会再次获取新记录但这些记录没有呈现
    • @UsamaJaved 因为您的 table() 函数上的 setState 包含 UI 元素,如果您阅读我的回答,我给出了一个示例代码,您的 setState 将不再包含 UI 元素,您可以试试
    猜你喜欢
    • 2021-04-28
    • 1970-01-01
    • 1970-01-01
    • 2019-11-19
    • 1970-01-01
    • 2019-04-03
    • 1970-01-01
    • 2023-01-04
    • 2020-01-13
    相关资源
    最近更新 更多