Send a update and delete requests without refreshing frontend

Viewed 57

I'm trying to send update and delete request without actually refreshing my frontend. So, I know that e.preventDefault() will prevent my frontend to refresh whenever I send in fetch request. However, I have to refresh the page to actually change the frontend after the request.

My frontend looks like this.

Image after clicking update button on the white card

What I want is to show the change within the frontend without refreshing the page. Also, I would like to pre-fill those textareas with values that already exist (I don't want to use placeholder). Please help.

import { useState } from 'react';

export default function PostContainer({post}){
    const [isShown, setIsShown] = useState(false);
    const [title, setNewTitle] = useState("");
    const [content, setNewContent] = useState("");
    const [tags, setNewTags] = useState("");
    const userId = post.user_id

    console.log(post)

    function handleDelete(e){
        e.preventDefault();
        fetch(`/post/${post.id}`,{
            method: "DELETE",
            headers: {
                'Content-Type':'application/json'
            },
            body: JSON.stringify(post)
        })
        .then((r) => r.json())
        .then(alert("Post Removed"))
    }

    // Display update component
    const handleUpdate = (e) =>{
        e.preventDefault();
        setIsShown(current => !current)
    }

    // Send patch requests
    function handleSubmit(e){
        e.preventDefault();
        const patchedPost = {
            title,
            content,
            userId,
            tags_attributes: tags.split(',').map((el) => { return {name: el} })
        }

        fetch(`/post/${post.id}`, {
            method: "PATCH",
            headers: {
                "Content-Type": "application/json"
            },
            body: JSON.stringify(patchedPost)
        })
        .then((r)=>r.json())
        .then((x) => console.log(x)) 
    }
    
    return(
    <div>
        <div>
        {isShown && (
            <div>
                <form className='update-form' onSubmit={handleSubmit}>
                    <label>Title</label><br/>
                    <textarea type='text'  placeholder={post.title} value={title} onChange={(e)=>setNewTitle(e.target.value)}></textarea><br/>
                    <label>Content</label><br/>
                    <textarea type='text'  placeholder={post.content} value={content} onChange={(e)=>setNewContent(e.target.value)}></textarea><br/>
                    <label>Tags</label><br/>
                    <textarea type='text' placeholder={post.tags.name} value={tags} onChange={(e)=>setNewTags(e.target.value)}></textarea><br/>
                    <button type='submit'>Update</button>
                    <button onClick={(e)=>{e.preventDefault(); setIsShown(false)}}>Cancel</button>
                </form>
            </div>
        )}
        </div><br/>
        <div className='postContainer'>
            <h1>{post.title}</h1>
            <p className="users-posts-content">{post.content}</p>
            <p>Tags: {post.tags.map((x)=> x.name).join(', ')}</p>
            <button onClick={(e)=>handleUpdate(e)}>Update</button> 
            <button onClick={(e)=>handleDelete(e)}>Delete Post</button>
        </div>
    </div>
    )
}
1 Answers

When you call handleDelete() method, you delete post by id, but after that you didnt refresh state of all your posts.

I'd do it something like that. In the PostsContainer I have GET-request which gets all posts, then updates state with all actual posts from the server via setPosts() and then re-render all posts on the page in a cycle:

//PostsContainer.jsx
import {useState, useEffect} from 'react'
import Post from './Post'

function PostsContainer() {
  const [posts, setPosts] = useState('');

  useEffect(() => {
   getPosts()
  }, [])

  const getPosts = () => {
     fetch('/posts')
    .then(response => response.json())
    .then(json => setPosts(json.posts))
  }

  return (
    <div>
        {
          posts 
            && posts.map(post => <Post key={post.id} post={post} getPosts={getPosts}/>)
        }
    </div>
  );
}
export default PostsContainer

And in Post.jsx I pass getPosts() method, which will call after I succefuly delete post:

//Post.jsx
function Post({ post, getPosts }) {
  
  const deletePost = (id) => {
    fetch(`/posts/${id}`, {
      method: 'DELETE',
    })
      .then(res => res.json())
      .then(res => {
        if (res.status === 200) {
          getPosts()
        }
      })
      .catch(err => alert(err.message))
  }

  return (
    <div>
      <div>{post.id}</div>
      <div>{post.title}</div>
      <button onClick={() => deletePost(post.id)}>Delete post</button>
    </div>
  )
}
export default Post;

Thus, getPosts(), passed in Post.jsx, makes requests to the server, gets actual array of posts from db, then updates the state of all posts, then your posts will be re-rendered without page reloading

Related