React — Deleting from state?

Hey guys, I have functionality that is unbelievably shaky and I cannot consistently recreate the problem.

I am getting a collection and setting it to state like so:

  // Get Art
  useEffect(() => {
    async function getArtList() {
      // Load the art collection
      const artListJson = await fetch(`${API}/chizetteart`)
      const artList = await artListJson.json()

      // Filter artList and set to current state
      setArtList(filterArtList(artList))
    }
    getArtList()
  }, [filteredTerm])

And the delete seems to be partially broken where it returns a 404 sometimes when trying to delete, but other times it works fine.

  // Admin — Delete art
  const deleteArt = async (id) => {
    let response = await fetch(`${API}/chizetteart/${id}`, {
      method: "DELETE",
      mode: "cors",
      headers: {
        "Accept": "application/JSON",
        "Content-Type": "application/json",
        "token": token.token
      },
    })
    if (response.status !== 200) {
      setMessage("Unable to delete art.")
      setOpen(true)
      setSeverity("error")
    } else {
      setMessage("Crumbled up and thrown away!")
      setOpen(true)
      setSeverity("success")
    }
    setArtList([...artList])
  }

What could be the cause of this? Sometimes I have to refresh the page, then delete which seems to work as well, but it isn’t 100% consistent. Any idea here would be awesome.

1 Like

What happens if you put your await fetch(s) inside try/catch blocks? In getArtList you may also want to check the ok property on the response as well.

1 Like

I realized when you showed me code dealing with the snackers…this is probably what I should’ve done, huh? I thought the problem was maybe having the entire list in the state and it wasn’t being updated. I will absolutely try to get it to use try / catch blocks.

1 Like

Well, I can’t say that it is the problem I just know when using async/await you need to still catch and that is usually done using a try/catch. Just like when you used .then() you have a .catch().

You want to catch network errors and check the response.

Checking that the fetch was successful

A fetch() promise will reject with a TypeError when a network error is encountered or CORS is misconfigured on the server-side, although this usually means permission issues or similar — a 404 does not constitute a network error, for example. An accurate check for a successful fetch() would include checking that the promise resolved, then checking that the Response.ok property has a value of true.

  // Admin — Delete art
  const deleteArt = async (id) => {
    try {
      let response = await fetch(`${API}/chizetteart/${id}`, {
        method: "DELETE",
        mode: "cors",
        headers: {
          "Accept": "application/JSON",
          "Content-Type": "application/json",
          "token": token.token
        },
      })
      if (response.ok) {
        setMessage("Crumbled up and thrown away!")
        setOpen(true)
        setSeverity("success")
      } else {
        setMessage("Res not OK.")
        setOpen(true)
        setSeverity("warning")
      }
    } catch (err) {
      setMessage("Unable to delete art.")
      setOpen(true)
      setSeverity("error")
    }
    setArtList([...artList])
  }

So, it is hitting the else on any time it fails. It brings back a 404 through the server, but it never hits the “err”

Might be a problem with the endpoint or the supplied data to the endpoint.

Yeah, I would imagine that is it. I’ve stared at the frontend code for months now.

Here is the route. I am going to see if it is something with the token in the header not always being passed. I’m not quite sure…

// Delete one record
router.delete('/:id', jwtVerify, checkIdisNum, (req, res, next) => {
  knex('chizetteart')
    .where('id', req.params.id)
    .first()
    .then((row) => {
      if(!row) return next()
      knex('chizetteart')
        .del()
        .where('id', req.params.id)
        .then(() => {
          res.send(`ID ${req.params.id} Deleted`)
        })
    })
    .catch((err) => {
      next(err)
    })
})

I’d also log the id in the deleteArt function just to see if you are always getting what you expect.

Do you have a logger on the back-end, like morgan?

See if you can trigger something that is reproducible, it might not be as random as it first appears to be.

1 Like

I do have morgan installed, yeah. Honestly I have never used it. This was from learning Node over a year ago.

Screen Shot 2020-03-25 at 5.32.37 PM
I don’t know what to draw from this. On the 200’s it passes the ID through req.params.id, yet on the 404’s, nothing is passed through.

I’m guessing you have to check how deleteArt is getting the id and if something is wrong somewhere. Sounds like the fetch might not be getting the id sometimes.

Weird stuff, but the ev.target when the function is called, fails and reads just the icon, but when it works, it pulls in extra properties, including the ID…

Screen Shot 2020-03-25 at 5.52.21 PM

Oh my god, I have to literally click outside of the button? This must be propagation?

Well, that is a little hard for me to troubleshoot.

Sounds like the handler is firing on the wrong element. You can do a check on the event target to make sure you are not calling the delete function unless the correct element was clicked.

If I click directly on the icon, it won’t work. I have to click right to the side of it which is very odd.

            <div className="deleteContainer">
              <DeleteForeverIcon 
                id={art.id}
                onClick={(ev) => removeArt(ev)}
                className="deleteIcon"
                fontSize="large"
              />
            </div>

That might just be a CSS issue as well. Check the element the handler is attached to. Make sure it’s not collapsed, somehow un-clickable, other elements in front, z-index issues, etc.

Nothing in the CSS seems to be blocking it. Even sometimes it works when I click on the icon, reading the parent element and not the <path>…but I realize that is just clicking on the white space behind the SVG (being the parent.) So 100% now it is just the SVG blocking the event.

Screen Shot 2020-03-25 at 6.22.36 PM

Can you move the onClick to the div container?

1 Like

That had the same effect. I just solved it with:

#parentDiv * {
    pointer-events: none
}
1 Like