将dom从子组件更新为父组件

时间:2020-07-12 07:05:45

标签: reactjs react-hooks

我在子组件中调用axios delete方法,并希望刷新父组件以作出反应。当delete()调用时,它从数据库中删除了该行,但需要手动重新加载。没有手动重新加载怎么办?

我想删除方法,并且ProductList.js也同时更新。

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

class ProductList extends Component {
  constructor(props) {
    super(props);
    this.state = { productData: [] };
  }
  componentDidMount() {
    axios
      .get("http://localhost:8080/products")
      .then((response) => {
        console.log("responseProductList==", response);
        this.setState({ productData: response.data });
      })
      .catch(function (error) {
        console.log(error);
      });
  }
  tabRow() {
    return this.state.productData.map(function (object, i) {
      return <Table obj={object} key={i} />;
    });
  }
  render() {
    return (
      <div style={{ paddingTop: "25px" }}>
        <h4 align="center">Product List</h4>
        <table className="table table-striped" style={{ marginTop: 10 }}>
          <thead>
            <tr>
              <th>Id</th>
              <th>Name</th>
              <th>Price</th>
              <th colSpan="4">Action</th>
            </tr>
          </thead>
          <tbody>{this.tabRow()}</tbody>
        </table>
      </div>
    );
  }
}

export default ProductList;

import React, { Component } from "react";
import axios from "axios";
import { Link, withRouter } from "react-router-dom";

// import ProductList from "./ProductList";
// import AddProduct from "./AddProduct";

class Table extends Component {
  // constructor(props) {
  //   super(props);
  // }

  deleteProduct = () => {
    console.log("delete button clicked");
    axios
      .delete("http://localhost:8080/products/" + this.props.obj.id)
      .then((res) => {
        if (res.status === 200) {
          alert("getStatusInDelete");
          // return axios.get("http://localhost:8080/products/");
          // this.forceUpdate(<ProductList />);
          this.props.history.push("/ProductList");
        } else {
          console.log("Not refresh");
        }
      })
      .catch((err) => console.log(err));
  };

  render() {
    return (
      <tr>
        <td>{this.props.obj.id}</td>
        <td>{this.props.obj.name}</td>
        <td>{this.props.obj.price}</td>
        <td>
          <Link
            to={"/EditProduct/" + this.props.obj.id}
            className="btn btn-success"
          >
            Edit
          </Link>
        </td>
        <td>
          <button
            type="button"
            onClick={this.deleteProduct}
            className="btn btn-danger"
          >
            Delete
          </button>
        </td>
      </tr>
    );
  }
}

export default withRouter(Table);

3 个答案:

答案 0 :(得分:2)

成功删除产品后,您需要更新父状态。

方法是在父组件中定义更新逻辑,然后在删除成功后从子组件中调用该函数。

// Define your update product logic here 
// It will get productId (or any other unique key) as parameter
// and will use that unique key to update the producsts 
// I've added an example logic but yours can be different
updateProducts = (productId) => {
    let productsClone = { ...this.state.productData };
    const productIndex = productsClone.findIndex(item => item.id == productId);

    if (productIndex > -1) {
        productsClone.splice(productIndex, 1);
        this.setState({ productData: productsClone });
    }
}

tabRow() {
    return this.state.productData.map(function (object, i) {
    // pass your `this.updateProducts` as a props to your child component
        return <Table obj={object} key={i} updateProducts={this.updateProducts} />;
    });
}

deleteProduct = () => {
    axios
        .delete("http://localhost:8080/products/" + this.props.obj.id)
        .then((res) => {
            if (res.status === 200) {
                // Finally, here, call the updateProucts when API return success and make sure to pass the correct key as a parameter    
                this.props.updateProducts(res.data.id);
            } else {
                console.log("Not refresh");
            }
        })
        .catch((err) => console.log(err));
};

答案 1 :(得分:2)

首先,您不应使用索引作为键,而应使用产品的ID,因为如果使用索引,则删除后可能会遇到奇怪的错误。 要更新列表,我将传递一个回调onDelete(id)并在父级中处理它。 像这样:

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

class ProductList extends Component {
  constructor(props) {
    super(props);
    this.state = { productData: [] };
  }
  componentDidMount() {
    axios
      .get("http://localhost:8080/products")
      .then((response) => {
        console.log("responseProductList==", response);
        this.setState({ productData: response.data });
      })
      .catch(function (error) {
        console.log(error);
      });
  }

  //****** This is the callback you are going to pass ********
  onProductDeleted = (id) => {
    this.setState((state) => ({  productData: state.productData.filter(x => x.id !== id) })
  }
  
  tabRow() {
    return this.state.productData.map(object => {
      //********* Passing the callback ************
      return <Table obj={object} key={object.id} onDeleted={this.onProductDeleted} />;
    });
  }
  render() {
    return (
      <div style={{ paddingTop: "25px" }}>
        <h4 align="center">Product List</h4>
        <table className="table table-striped" style={{ marginTop: 10 }}>
          <thead>
            <tr>
              <th>Id</th>
              <th>Name</th>
              <th>Price</th>
              <th colSpan="4">Action</th>
            </tr>
          </thead>
          <tbody>{this.tabRow()}</tbody>
        </table>
      </div>
    );
  }
}

export default ProductList;

import React, { Component } from "react";
import axios from "axios";
import { Link, withRouter } from "react-router-dom";

class Table extends Component {

  deleteProduct = () => {
    console.log("delete button clicked");
    axios
      .delete("http://localhost:8080/products/" + this.props.obj.id)
      .then((res) => {
        if (res.status === 200) {
          alert("getStatusInDelete");
          this.props.history.push("/ProductList");
          
          //****** Invoke the callback after successfully deleted *****
          this.props.onDeleted(this.props.obj.id);
          
        } else {
          console.log("Not refresh");
        }
      })
      .catch((err) => console.log(err));
  };

  render() {
    return (
      <tr>
        <td>{this.props.obj.id}</td>
        <td>{this.props.obj.name}</td>
        <td>{this.props.obj.price}</td>
        <td>
          <Link
            to={"/EditProduct/" + this.props.obj.id}
            className="btn btn-success"
          >
            Edit
          </Link>
        </td>
        <td>
          <button
            type="button"
            onClick={this.deleteProduct}
            className="btn btn-danger"
          >
            Delete
          </button>
        </td>
      </tr>
    );
  }
}

export default withRouter(Table);

以下是一些您可以参考的资料,可以增进您对React的理解:

  1. 状态更新可能是异步的:https://reactjs.org/docs/state-and-lifecycle.html#state-updates-may-be-asynchronous

  2. 这就是为什么使用索引作为键可能不是一个好主意:https://medium.com/@vraa/why-using-an-index-as-key-in-react-is-probably-a-bad-idea-7543de68b17c

答案 2 :(得分:0)

最终答案:经过稍微编辑,现在可以正常使用。

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

class ProductList extends Component {
  constructor(props) {
    super(props);
    this.state = { productData: [] };
  }
  componentDidMount() {
    axios
      .get("http://localhost:8080/products")
      .then((response) => {
        console.log("responseProductList==", response);
        this.setState({ productData: response.data });
      })
      .catch(function (error) {
        console.log(error);
      });
  }

  //****** This is the callback you are going to pass ********
  onProductDeleted = (id) => {
    this.setState((state) => ({  productData: state.productData.filter(x => x.id !== id) })
    )}
  
  tabRow = () => {
    return this.state.productData.map(object => {
      //********* Passing the callback ************
      return <Table obj={object} key={object.id} onDeleted={this.onProductDeleted} />;
    });
  }
  render() {
    return (
      <div style={{ paddingTop: "25px" }}>
        <h4 align="center">Product List</h4>
        <table className="table table-striped" style={{ marginTop: 10 }}>
          <thead>
            <tr>
              <th>Id</th>
              <th>Name</th>
              <th>Price</th>
              <th colSpan="4">Action</th>
            </tr>
          </thead>
          <tbody>{this.tabRow()}</tbody>
        </table>
      </div>
    );
  }
}

export default ProductList;

import React, { Component } from "react";
import axios from "axios";
import { Link, withRouter } from "react-router-dom";

class Table extends Component {
  deleteProduct = () => {
    console.log("delete button clicked");
    axios
      .delete("http://localhost:8080/products/" + this.props.obj.id)
      .then((res) => {
        if (res.status === 200) {
          alert("getStatusInDelete");
          // this.props.history.push("/ProductList");

          //****** Invoke the callback after successfully deleted *****
          this.props.onDeleted(this.props.obj.id);
        } else {
          console.log("Not refresh");
        }
      })
      .catch((err) => console.log(err));
  };

  render() {
    return (
      <tr>
        <td>{this.props.obj.id}</td>
        <td>{this.props.obj.name}</td>
        <td>{this.props.obj.price}</td>
        <td>
          <Link
            to={"/EditProduct/" + this.props.obj.id}
            className="btn btn-success"
          >
            Edit
          </Link>
        </td>
        <td>
          <button
            type="button"
            onClick={this.deleteProduct}
            className="btn btn-danger"
          >
            Delete
          </button>
        </td>
      </tr>
    );
  }
}

export default withRouter(Table);