babla19830
babla19830

Reputation: 87

React refresh the page after delete button

The delete function of my app is working fine, however it requires the user to manually refresh the page after the user click the delete button in order to see the new list of elements in my database. I would like to automatically refresh after the click event. I am using react hooks for this projects. However, I found one solution if I remove useEffect's [] but in my backend it shows, its requesting crazily. I don't know, is it wise to remove useffect's [ ]?

Here is the component where it fetches data from backend and passes the props to another component

 import React, { useState, useEffect } from "react";
    import axios from "axios";
    import Table from "../Table/Table";
    import "./Display.css";
    const Display = () => {
      const [state, setState] = useState({ students: [], count: "" });
      const [searchItem, setsearchItem] = useState({
        item: ""
      });

      const Search = e => {
        setsearchItem({ item: e.target.value });
      };

      useEffect(() => {
        axios
          .get("/students")
          .then(response => {
            setState({
              students: response.data.students,
              count: response.data.count
            });
          })
          .catch(function(error) {
            console.log(error);
          });
      }, []); //If I remove this square brackets, it works 
      const nameFilter = state.students.filter(list => {
        return list.name.toLowerCase().includes(searchItem.item.toLowerCase());
      });

      return (
        <div>
          <h3 align="center">Student tables</h3>
          <p align="center">Total students: {state.count}</p>
          <div className="input-body">
            <div className="row">
              <div className="input-field col s6">
                <input placeholder="search student" onChange={Search} />
              </div>
            </div>
          </div>

          <table className="table table-striped">
            <thead>
              <tr>
                <th>Name</th>
                <th>Date of birth</th>
                <th>Address</th>
                <th>Zipcode</th>
                <th>City</th>
                <th>Phone</th>
                <th>Email</th>
                <th colSpan="2">Action</th>
              </tr>
            </thead>
            {nameFilter.map((object, index) => {
              return (
                <tbody key={index}>
                  <Table obj={object} /> //In here I am passing the props to the another component.
                </tbody>
              );
            })}
          </table>
        </div>
      );
    };

    export default Display;

This is second component which receives the props.

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

const Table = props => {
  const removeData = () => {
    axios
      .delete("/students/" + props.obj.id)
      .then(console.log("Deleted"))
      .catch(err => console.log(err));
  };

  return (
    <React.Fragment>
      <tr>
        <td>{props.obj.name}</td>
        <td>{props.obj.birthday}</td>
        <td>{props.obj.address}</td>
        <td>{props.obj.zipcode}</td>
        <td>{props.obj.city}</td>
        <td>{props.obj.phone}</td>
        <td>{props.obj.email}</td>
        <td>
          <Link
            to={"/edit/" + props.obj.id}
            className="waves-effect waves-light btn"
          >
            Edit
          </Link>
        </td>
        <td>
          <button onClick={removeData} className="waves-effect red btn ">
            Remove
          </button>
        </td>
      </tr>
    </React.Fragment>
  );
};

export default Table;

Upvotes: 2

Views: 12180

Answers (3)

Mesh Mesh
Mesh Mesh

Reputation: 1

Have a look at this

import React, { useState } from "react";

const Display = () => {

    const [refresh, setRefresh] = useState(false)

    const delete=() => {
    // ................. //delete logic
        reload ? setRefresh(false) : setRefresh(true) //toggle just to change state
   }
    useEffect(() => {

    }, [reload]); //inject as dependency
}

Upvotes: 0

jean182
jean182

Reputation: 3505

Not sure if helps but you can always remove the item from the current array, so a refresh is not needed, for example you can pass as props a function that receives an id and then filter the students array to exclude the element that matches with that id and then update the state with the new array and count properties, something like this

In your parent:

  const Display = () => {
   const [state, setState] = useState({ students: [], count: "" });

   const deleteItem = (id) => {
    const newStudents = state.students.filter(student => student.id !== id)
    const newCount = newStudents.length;
    setState({ students: newStudents, count: newCount })
   }
  // Rest of the code
  }

Now pass that function to your child component.

<Table obj={object} deleteItem={deleteItem} />

In the child component just modify your removeData method to add the deleteItem prop:

  const Table = props => {
   const removeData = () => {
    axios
     .delete("/students/" + props.obj.id)
     .then(console.log("Deleted"))
     .catch(err => console.log(err));
    // Now if your request succeeds call the function to remove the item from the students state array
   props.deleteItem(props.obj.id);

   };
 // Rest of the code
 }

I know this does not answer your question, but when you're working with react or it is better to do this computations and filters on the app side, like in this case that even though the record was deleted from the db we also removed the record from the student state object and there's no need to refresh the page.

Remember, you're creating a single page application, so we want the nicest experience for the user without refreshing the page for every action the user makes.

Upvotes: 0

Nick
Nick

Reputation: 16576

The [] in the useEffect hook is a dependency array to trigger the effect to run. If you want to trigger the effect (without it going off mercilessly), you can create a new variable that triggers that effect to run.

import React, { useState, useEffect } from "react";
import axios from "axios";
import Table from "../Table/Table";
import "./Display.css";

const Display = () => {
  const [state, setState] = useState({ students: [], count: "" });
  const [requestData, setRequestData] = useState(new Date());
  const [searchItem, setsearchItem] = useState({
    item: ""
  });

  const Search = e => {
    setsearchItem({ item: e.target.value });
  };

  useEffect(() => {
    axios
      .get("/students")
      .then(response => {
        setState({
          students: response.data.students,
          count: response.data.count
        });
      })
      .catch(function(error) {
        console.log(error);
      });
  }, [requestData]);

  const nameFilter = state.students.filter(list => {
    return list.name.toLowerCase().includes(searchItem.item.toLowerCase());
  });

  return (
    <div>
      <h3 align="center">Student tables</h3>
        <p align="center">Total students: {state.count}</p>
        <div className="input-body">
          <div className="row">
            <div className="input-field col s6">
              <input placeholder="search student" onChange={Search} />
            </div>
          </div>
        </div>
        <table className="table table-striped">
          <thead>
            <tr>
              <th>Name</th>
              <th>Date of birth</th>
              <th>Address</th>
              <th>Zipcode</th>
              <th>City</th>
              <th>Phone</th>
              <th>Email</th>
              <th colSpan="2">Action</th>
            </tr>
          </thead>
          {nameFilter.map((object, index) => {
            return (
              <tbody key={index}>
                <Table obj={object} setRequestData={setRequestData} />
              </tbody>
            );
          })}
        </table>
      </div>
    );
  };

export default Display;

Then you can trigger it from your Table component:

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

const Table = props => {
  const removeData = () => {
    axios
      .delete("/students/" + props.obj.id)
      .then(() => {
        props.setRequestData(new Date());
      })
      .catch(err => console.log(err));
  };

  return (
    <React.Fragment>
      <tr>
        <td>{props.obj.name}</td>
        <td>{props.obj.birthday}</td>
        <td>{props.obj.address}</td>
        <td>{props.obj.zipcode}</td>
        <td>{props.obj.city}</td>
        <td>{props.obj.phone}</td>
        <td>{props.obj.email}</td>
        <td>
          <Link
            to={"/edit/" + props.obj.id}
            className="waves-effect waves-light btn"
          >
            Edit
          </Link>
        </td>
        <td>
          <button onClick={removeData} className="waves-effect red btn ">
            Remove
          </button>
        </td>
      </tr>
    </React.Fragment>
  );
};

export default Table;

Upvotes: 8

Related Questions