обновить dom от дочернего компонента до родительского компонента - PullRequest
2 голосов
/ 12 июля 2020

Я вызываю метод ax ios delete в дочернем компоненте и хочу обновить sh родительский компонент для реакции. При вызове функции 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 ]

2 голосов
/ 12 июля 2020

Прежде всего, вы не должны использовать индекс в качестве ключа, а вместо этого используйте идентификатор продукта, потому что, если вы используете индекс, вы можете столкнуться с странными ошибками после удаления. Чтобы обновить список, я бы передал обратный вызов 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);

Вот несколько источников go, которые улучшат ваше понимание 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-response-is-вероятно-a-bad-idea-7543de68b17 c

2 голосов
/ 12 июля 2020

Вам необходимо обновить родительское состояние, когда продукт будет успешно удален.

Это можно сделать, определив лог c обновления в родительском компоненте, а затем вызовите эту функцию из дочернего компонента при успешном удалении.

// 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));
};
0 голосов
/ 12 июля 2020

Окончательный ответ: он немного отредактирован и теперь работает нормально.

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);
...