How to delete from Firebase with React? - reactjs

I'm trying to add a delete button to a post so that I can delete individual posts from a channel. I'm using Firebase as my database and the posts collections are nested within channels collection. I added a button to each post, created an onClick event called handleDel, I've tried finding the post inside the channel collection and deleting it but I can't delete my post.
const db = firebaseApp.firestore()
Post.js
function Post({ user, post, timestamp }) {
const channelId = useSelector(selectChannelId)
const handleDel = () => {
db.collection('channels')
.doc(channelId)
.collection('posts')
.doc(post).delete().then(() => {
console.log("Document successfully deleted!");
}).catch((error) => {
console.error("Error removing document: ", error);
});
}
return (
<div className='post'>
<Avatar src={user.photo}
/>
<div className="post__content">
<h4>{user.displayName}
<span className='post__timestamp'>
<ClearIcon
className='clearIcon'
onClick={handleDel}
id={post.id}
/>
{new Date(timestamp?.toDate()).toUTCString()}
</span>
</h4>
<p className='post__text'>
{post}
</p>
</div>
</div>
)
}
Posts.js for more context
function Posts() {
const user = useSelector(selectUser)
const channelId = useSelector(selectChannelId)
const channelName = useSelector(selectChannelName)
const [input, setInput] = useState('')
const [posts, setPosts] = useState([])
useEffect(() => {
if (channelId) {
db.collection('channels')
.doc(channelId)
.collection('posts')
.orderBy('timestamp', 'asc')
.onSnapshot((snapshot) =>
setPosts(snapshot.docs.map(doc => ({...doc.data(), id: doc.id})))
)
}
}, [channelId])
const sendPost = e => {
e.preventDefault()
db.collection('channels')
.doc(channelId)
.collection('posts')
.add({
timestamp: firebase.firestore.FieldValue.serverTimestamp(),
post: input,
user: user,
})
setInput('')
}
return (
<div className='posts__container'>
<ChannelTitle channelName={channelName} />
<div className="posts">
{posts.map((post) => (
<Post
timestamp={post.timestamp}
post={post.post}
user={post.user}
id={post.id}
key={post.id}
/>
))}
</div>
<div className="post__input">
<AddCircleIcon />
<form>
<input
type="text"
placeholder={`Post to #${channelName}`}
value={input}
disabled={!channelId}
onChange={e => setInput(e.target.value)}/>
<button
type='submit'
className='post__inputButton'
onClick={sendPost}>
Send</button>
</form>
<div className="post__inputIcons">
<GifIcon />
<EmojiEmotionsIcon />
</div>
</div>
</div>
)
}
I've also tried
const handleDel = () => {
db.collection('posts')
.doc(post).delete().then(() => {
console.log("Document successfully deleted!");
}).catch((error) => {
console.error("Error removing document: ", error);
});
}
and
const handleDel = () => {
db.collection('channels')
.doc(channelId)
.collection('posts')
.doc(post.id).delete().then(() => {
console.log("Document successfully deleted!");
}).catch((error) => {
console.error("Error removing document: ", error);
});
}
My console says "Document successfully deleted!" but the post is still in the database and still shows. Any insight would be appreciated.

Take a look at these lines:
(<Post
timestamp={post.timestamp}
post={post.post}
user={post.user}
id={post.id}
key={post.id}
/>)
function Post({ user, post, timestamp }) {
Here, you pass in the properties id, post, timestamp, and user into your component but only pull out post, timestamp, and user. In addition, post here is not the post object (that has id, timestamp, etc inside it) but is the text content of the post, originally the value of input when posted, as a string. This means that your Post component doesn't know it's own ID as post.id in this case would be undefined. Plus, because you are deleting the document using .doc(post), the delete operation succeeds because you end up deleting a document that is named with the content of your message like /channels/${channelId}/posts/"This is my message!" instead of what you are trying to delete, which is /channels/${channelId}/posts/${postId}.
To correct this, you would change it to:
function Post({ id: postId, user, post, timestamp }) {
const channelId = useSelector(selectChannelId)
const handleDel = () => {
return db.collection('channels') // note return of promise chain
.doc(channelId)
.collection('posts')
.doc(postId)
.delete()
.then(
() => {
console.log("Document successfully deleted!");
},
(error) => {
console.error("Error removing document: ", error);
}
);
}
/* ... rest of component ... */
}
Other things of concern:
Rename your document's post field to content or similar to disambiguate between your post as a whole and its content
Use postData instead of just post and postDataList/postDataArray instead of just posts to disambiguate them or make use of TypeScript to help catch these typos
For each post, you are calling useSelector to obtain the channelId. Which is fine, but as there is a clear parent-child relationship here, you could pass in the channelId along with the post's data from your Posts component for improved performance.
The channel listener (useEffect(/* ... */, [channelId])) doesn't clean up after itself
The posts in the channel are not paginated. (Imagine a month-old conversation chain of hundreds of messages with at least 10 users listening to the channel - do all of those users need all of those messages at once? - that's 1000+ document reads when you might only need 10 per user)
The sendPost click handler doesn't wait for confirmation that the message was send before clearing it's input
The sendPost click handler doesn't show an error when channelId is falsy
The sendPost click handler doesn't show an error on failure to add the message to the database
The sendPost click handler allows posting empty messages
The Send button is not disabled when channelId is falsy
The value of user isn't error-checked, it is also unclear if this is a User object, their name or their UID.

Try this.
You need to pass unique id of post/list in API call to delete specific database entry
improved
<ClearIcon
className='clearIcon'
onClick={() => handleDel(post.id)}
id={post.id}
/>
function
const handleDel = (id) => {
db.collection('channels')
.doc(channelId)
.collection('posts')
.doc(id).delete().then(() => {
console.log("Document successfully deleted!");
}).catch((error) => {
console.error("Error removing document: ", error);
});
}

Related

React useState object not letting me access it's properties

I'm making a chat app and I'm trying to create dynamic chat pages based on room page names within firestore. My chat component updates the chatbox title depending on what it finds off of firestore. I have determined that the query I'm using does in fact pull the data correctly through console.log.
function Chat() {
const { roomId } = useParams();
const [roomDetails, setRoomDetails] = useState();
useEffect(() => {
const roomQuery = query(
collection(db, "rooms"),
where("name", "==", roomId)
);
if (roomId) {
const unsubscribe = onSnapshot(roomQuery, (snapshot) => {
setRoomDetails(snapshot.docs.map((doc) => ({ ...doc.data() })));
});
return () => {
unsubscribe();
};
}
}, [roomId]);
console.log(roomDetails);
return (
<div className="chat">
<div className="chat__header">
<div className="chat__headerLeft">
<h4 className="chat__channelName">
<strong>#{roomDetails?.name}</strong>
<StarBorderOutlinedIcon />
</h4>
</div>
<div className="chat__headerRight">
<p>
<InfoOutlinedIcon /> Details
</p>
</div>
</div>
</div>
);
}
What doesn't work is the bottom section
<h4 className="chat__channelName">
<strong>#{roomDetails?.name}</strong>
<StarBorderOutlinedIcon />
</h4>
Within my browser the chat title will be blank and I presume that it's because it isn't reading the data or the data isn't defined yet. Here is what the useState looks like in console.
console.log output
[{…}]0:
{name: 'general'}
length: 1
[[Prototype]]: Array(0)
Here's what Firestore looks like
I found the solution I changed the way the Data was updated into the useState
useEffect(() => {
const roomQuery = query(
collection(db, "rooms"),
where("name", "==", roomId)
);
if (roomId) {
const unsubscribe = onSnapshot(roomQuery, (snapshot) => {
setRoomDetails(snapshot.docs.at(0).data());
});
return () => {
unsubscribe();
};
}
}, [roomId]);
The way the data is rendered is the same. Hope this helps some future people.

How can I show my backend api errors via the UI with axios React?

I have form validation set up on the backend. I want to display this validation to the user on the front end. I have a component that contains a popup modal. Inside that component, I am trying to catch errors inside my useEffect and my onSubmit function. And am trying to display those errors on the modal when the user tries to submit an incorrect value, for instance the user enters a password that isn't long enough.
What I am doing now, is not even catching the errors nor displaying them. If I leave an input blank it should show that error message. I am currently displaying errors via the UI from the UpdateValidation(). That will be removed once I am able to display the errors via the backend.
function EditModal({ close, companyId, employeeId }) {
const { formValidation, formData, setFormData, firstNameError, lastNameError, emailError } = UpdateValidation();
const isVisible = !!userId;
const [errors, setErrors] = useState([])
const handleChange = (e: any) => {
setFormData({
...formData,
[e.target.name]: e.target.value.trim(),
});
};
useEffect(
() => {
if (employeeId !== null) {
axios.get(`${process.env.PUBLIC_URL}/api/company/${companyId}/employees/${employeeId}`)
.then(res => {
setFormData(res.data);
})
.catch(error => {
if (error.response) {
setErrors(error.response.data.errors);
}
})
}
}, [employeeId, setFormData, companyId])
const onSubmit = async (event: any) => {
event.preventDefault();
console.log(formData);
const isValid = formValidation();
if (isValid) {
await axios.put(`${process.env.PUBLIC_URL}/api/company/${companyId}/employees/${employeesId}`, formData)
.then((res) => {
setFormData(res.data);
})
.catch((error) => {
debugger;
if (error.response) {
setErrors(error.response.data.errors);
}
});
close();
}
};
Removing some of this for context, this is part of my modal
return (
<SprkModal
title="Update user:"
isVisible={isVisible}
confirmText="Submit"
cancelText="Cancel"
cancelClick={() => {
close();
}}
confirmClick={onSubmit}
>
<div className="modal">
{errors.length > 0 && (
<div className="errors">
<p>{errors}</p>
</div>
)}
<label>First Name: </label>
I am a new developer so any help will greatly be appreciated. I am not sure what I am doing wrong. I know the backend is set up correctly as I tested it with postman.
EDITOne reason this wasn't working was because of my if(isValid). Since my catch was within that block it wasn't getting hit because it wasn't valid so it would never hit the catch. I have since removed the isValid and am using a try catch.
try {
await axios.put(`${process.env.PUBLIC_URL}/api/company/${companyId}/employees`, formData)
.then((res) => {
setFormData(res.data);
close();
})
}
catch (error) {
debugger;
if (error.response) {
setErrors(error.response.data.errors);
console.log(error.response.status);
}
}
I can now see the errors in the console. But I am still not showing the errors on the UI. I thought that this setErrors(error.response.data.errors); would set the errors and I could retrieve them in the UI by doing this
<div className="modal">
{
errors.length > 0 && (
<div className="errors">
<p>{errors}</p>
</div>
)}
<label>First Name: </label>
But it doesn't hit the errors.length....I tried to console.log(errors) and got an empty array. When I check the react components I do see that the state is being set. I'm not sure how to display it on the UI.
Have you tried logging response.status in the console?
example:
if(response) {
console.log(response.status)
}
This doesn't solve your technical problem but might solve the actual problem which amounts to "how can i give feedback to my users". Are you using any view libraries?
Most libraries have components or functions that will do that for you.
In Ant Design they call it a 'message' -> https://ant.design/components/message/
In Material Ui they call it a 'snackbar' -> https://material-ui.com/components/snackbars/
Had to change this
{
errors.length > 0 && (
<div className="errors">
<p>{errors}</p>
</div>
)}
To this:
{Object.entries(errors).length > 0 &&
Object.entries(errors).map(([key, value]) => {
return <div key={value[0]}>{value[0]}</div>;
})}
And now it is working!

React: updating state after deletion

I'm trying to update elements after deletion, without refreshing a page. Currently, if delete a record, need to refresh a page to see the result. As I understand, need to update useState, but I do not understand how to do it. If I loop useEffect it works but slowly, but I think it's not the best idea to loop get response.
Get all records from a database.
const PostsGetUtill = () => {
const [posts, setPosts] = useState([]);
const fetchPosts = () => {
axios.get("api/v1.0/post/get").then(response => {
console.log(response.data);
setPosts(response.data);
}).catch(function (error) {
if (error.response) {
console.log(error.response.data);
console.log(error.response.status);
console.log(error.response.headers);
} else if (error.request) {
console.log(error.request);
} else {
console.log('Error', error.message);
}
console.log(error.config);
});
};
useEffect(() => {
fetchPosts();
}, []); // }, [fetchPosts]); <--- working well with loop
return (
<section className="container-post">
<PostMansonry posts={posts} columns={3} />
</section>
);
};
export default PostsGetUtill;
Sort and map records
export default function PostMansonry({ posts, columns }) {
return (
<section className="masonry" style={{ gridTemplateColumns: `repeat(${columns}, minmax(275px, 1fr))` }}>
{posts.sort((a, b) => a.zonedDateTime < b.zonedDateTime ? 1 : -1).map((posts, index) =>
<MasonryPost {...{ posts, index, key: index }} />)
}
</section>
)
}
Put data to the card
export default function MasonryPost({ posts, index }) {
return (
<div key={index} className="masonry-post">
<div className="card">
<div className="card-body">
<h5 className="card-title">{posts.title}</h5>
<p className="card-text">{posts.description}</p>
<p className="card-text"><small className="text-muted"> {posts.zonedDateTime}</small></p>
<div><button type="button" onClick={(e) => PostsDeleteUtill(posts.post_Id)} className="btn btn-danger">Delete</button></div>
</div>
</div>
</div>
)
}
Deleting
const PostsDeleteUtill = async (post_Id) => {
axios.delete(`api/v1.0/post/delete/${post_Id}`).then(response => {
console.log(response);
}).catch((error) => {
if (error.response) {
console.log(error.response.data);
console.log(error.response.status);
console.log(error.response.headers);
} else if (error.request) {
console.log(error.request);
} else {
console.log('Error', error.message);
}
console.log('error config', error.config);
});
};
export default PostsDeleteUtill;
Basically what you need to do is, in your PostsDeleteUtill function, in the promise return of your axios.delete, you need to update your posts state, which is set in PostsGetUtill.
In order to do that, you have 2 options:
Use a global state (React Context, Redux, etc)
Pass your setPosts handle all the way to your PostsDeleteUtill
I think option 1 is a bit cleaner for your specific case, but if you don't need global state anywhere else in your project, maybe it is fine to have a not so clean solution instead of implementing the whole global state structure for only one thing.
Option 1 pseudo code:
Your PostsGetUtill component would use a global state instead of local state:
const PostsGetUtill = () => {
// Remove this:
// const [posts, setPosts] = useState([]);
const fetchPosts = () => {
axios.get("api/v1.0/post/get").then(response => {
console.log(response.data);
// Instead of a local "setPosts" you would have a global
// "setPosts" (in Redux, this would be a dispatch)
dispatch({type: "PUT_POSTS", action: response.data})
}).catch(function (error) {
// No changes here...
});
};
// This runs only the first time you load this component
useEffect(() => {
fetchPosts();
}, []);
// Use your global state here as well:
return (
<section className="container-post">
<PostMansonry posts={globalState.posts} columns={3} />
</section>
);
};
export default PostsGetUtill;
In your PostsDeleteUtill function:
const PostsDeleteUtill = async (post_Id) => {
axios.delete(`api/v1.0/post/delete/${post_Id}`).then(response => {
// Update global state here. Probably filter the data to remove
// the deleted record
const updatedPosts = globalState.posts.filter(post => post.id !== response.data.id)
}).catch((error) => {
// No changes here
});
};
export default PostsDeleteUtill;
Option 2 pseudo code:
In your PostsGetUtill component, create and pass on a handleRemovePost:
// Your existing code ...
const handleRemovePost = (postID) => {
const filteredPosts = posts.filter(post => post.id !=== postID)
setPosts(filteredPosts)
}
return (
<section className="container-post">
<PostMansonry posts={posts} columns={3} handleRemovePost={handleRemovePost} />
</section>
);
In your PostMansonry, pass on again your handleRemovePost
export default function PostMansonry({ posts, columns, handleRemovePost }) {
return (
// Your existing code ...
<MasonryPost {...{ posts, index, key: index, handleRemovePost }} />)
)
}
Again in your MasonryPost
export default function MasonryPost({ posts, index, handleRemovePost }) {
return (
// Your existing code ...
<button type="button" onClick={(e) => PostsDeleteUtill(posts.post_Id, handleRemovePost)} className="btn btn-danger">Delete</button>
)
}
And finally:
const PostsDeleteUtill = async (post_Id, handleRemovePost) => {
axios.delete(`api/v1.0/post/delete/${post_Id}`).then(response => {
handleRemovePost(response);
})
};
PS: Please note that I only added a pseudo-code as a reference, trying to point out specific parts of the code that needs to be updated. If you need more information about global state, you can check React Context and Redux

React - How to find out the last document in a FireStore collection

The following component connects to a Cloud FireStore collection when it's mounted and shows only one document .limit(1).
Each time the user clicks the Next button a new request is sent to FireStore and shows the next document form the collection.
It's working fine. There's only one issue:
When the user clicks the Next button several times and reaches the last document inside the FireStore collection, the next click breaks the code, which makes sense.
I want that when the last document is reached, the next click on the Next button shows the first document or at least a message that the last item is reached.
How can I do this? How can I find out the last document in a FireStore collection?
import React, { useState, useEffect } from 'react';
import { db } from '../firebase';
const FlipCard = () => {
const [cards, setCards] = useState([]);
useEffect(() => {
const fetchData = async () => {
const data = await db
.collection('FlashCards')
.orderBy('customId', 'asc')
.limit(1)
.get();
setCards(data.docs.map((doc) => ({ ...doc.data(), id: doc.id })));
};
fetchData();
}, []);
const showNext = ({ card }) => {
const fetchNextData = async () => {
const data = await db
.collection('FlashCards')
.orderBy('customId', 'asc')
.limit(1)
.startAfter(card.customId)
.get();
setCards(data.docs.map((doc) => ({ ...doc.data(), id: doc.id })));
};
fetchNextData();
};
return (
<>
<div>
{cards.map((card) => (
<div className='card__face card__face--front'>
{<img src={card.imgURL} alt='' />}
{card.originalText}
</div>
<div className='card__face card__face--back'>
{card.translatedText}
</div>
</div>
))}
</div>
<div>
<button
onClick={() => showNext({ card: cards[cards.length - 1] })}
>
Next Card
</button>
</div>
</>
);
};
export default FlipCard;
The way to know that you're out of docs in a collection is when the number of results (cards.length) is smaller than the limit on the query (.limit(1)).
The code is breaking because it doesn't anticipate that condition:
onClick={() => showNext({ card: cards[cards.length - 1] })}
^ this expression might be -1
One way to fix is to conditionally render the button only if cards.length > 0.
Another way is to conditionally compute the parameter to showNext...
{ card: cards.length > 0 ? cards[cards.length - 1] : {} }
...and handle that case in the method.
just handle an error
const showNext = ({ card }) => {
const fetchNextData = async () => {
const data = await db
.collection('FlashCards')
.orderBy('customId', 'asc')
.limit(1)
.startAfter(card.customId)
.get()
.catch(error => { console.log('end of the row') });
if(!data.docs.length) console.log('end of the row');
setCards(data.docs.map((doc) => ({ ...doc.data(), id: doc.id })));
};
fetchNextData();
};

how to delete a single item using axios in react

I have looked into many articles and posts like this but it does not work in my case.I simply need to delete an item from my post list in my application using axios. In the axios docs it says you need to pass in the params to the delete method. Also I have sen in most apps they use ids without having ids in their state. But i cannot get it working. Please see my entire code. I know that my delete method is wrong please help me fix it:
// The individual post component
const Post = props => (
<article className="post">
<h2 className="post-title">{props.title}</h2>
<hr />
<p className="post-content">{props.content}</p>
<button onClick={props.delete}>Delete this post</button>
</article>
);
// The seperate form component to be written later
class Form extends React.Component {}
// The posts loop component
class Posts extends React.Component {
state = {
posts: [],
post: {
title: "",
content: ""
}
// error:false
};
componentDidMount() {
const { posts } = this.state;
axios
.get("url")
.then(response => {
const data = Object.values(response.data);
this.setState({ posts : data });
});
}
handleChange = event => {
const [name , value] = [event.target.name, event.target.value];
// const value = event.target.value;
const { post } = this.state;
const newPost = {
...post,
[name]: value
};
this.setState({ post: newPost });
};
handleSubmit = event => {
event.preventDefault();
const {post} = this.state;
const {posts} = this.state;
axios
.post("url", post)
.then(response => {
// console.log(response);
const newPost = Object.values(response.data);
this.setState({ post: newPost });
const updatedPosts = [...posts, {title:post.title,content:post.content}];
this.setState({ posts: updatedPosts});
// console.log(post);
console.log(updatedPosts);
console.log(this.state.posts);
});
};
handleDelete = () => {
const { post } = this.state;
axios.delete("url",{params: {id: post.id}})
.then(response => {
console.log(response);
});
};
render() {
let posts = <p>No posts yet</p>;
if (this.state.posts !== null) {
posts = this.state.posts.map(post => {
return <Post
key={post.id}
{...post}
delete={this.handleDelete}/>;
});
}
return (
<React.Fragment>
{posts}
<form className="new-post-form" onSubmit={this.handleSubmit}>
<label>
Post title
<input
className="title-input"
type="text"
name="title"
onChange={this.handleChange}
/>
</label>
<label>
Post content
<input
className="content-input"
type="text"
name="content"
onChange={this.handleChange}
/>
</label>
<input className="submit-button" type="submit" value="submit" />
</form>
</React.Fragment>
);
}
}
I also see this Error in console:
Uncaught (in promise) TypeError: Cannot convert undefined or null to object
at Function.values which is in get method.
Thanks again.
You are not specifying what your Post component should delete. In other words, the props.delete is not receiving an id to pass up to your parent component. In order to do that, you can change that to () => props.delete(props.id) and then in your parent component you need to have the handleDelete method receive the id of the item you want to target which is the id we passed up earlier from Post.
I don't know how your server is set up but using the axios request you originally have in your question your code would look like this:
handleDelete = (itemId) => {
// Whatever you want to do with that item
axios.delete("url", { params: { id: itemId } }).then(response => {
console.log(response);
});
Here's a CodeSandbox (using some dummy data in the constructor) displaying the item being passed in a console.log() (axios statement is commented out).
EDIT: How to make axios delete requests using Firebase REST API
Oh sorry, I did not see that you were using Firebase. Direct REST requests are a bit different with Firebase. In your configuration the requests should look like this:
axios.delete(`${url}/${firebasePostId}.json`).then(response => {
console.log(response)
})
This is assuming your Firebase rules allow unauthorized requests (which I strongly advise against, seeing as anyone could send this request).
Please note that firebasePostId is the push key provided by Firebase when you send POST requests to them, and are in fact a great choice of id for your posts. An example of one is -LOLok8zH3B8RonrWdZs which you mentioned in the comments.
For more information on Firebase REST API syntax, check out their documentation.
Thanks #FranklinFarahani. I had to write an answer as it is too long. I have changed my get and post method and managed to fix the delete method. I use the unique key that firebase is creating per post to delete each item. I get that inget method. This is the entire code.
// The individual post component
const Post = props => (
// use the key as an id here
<article id={props.id} className="post">
<h2 className="post-title">{props.title}</h2>
<hr />
<p className="post-content">{props.content}</p>
<button onClick={props.delete}>Delete this post</button>
</article>
);
// The Post lists component
class Posts extends React.Component {
state = {
posts: [],
post: {
id: "",
title: "",
content: ""
},
indexes: []
};
componentDidMount() {
const { posts } = this.state;
axios
.get("firebaseURL/posts.json")
.then(response => {
// create an array to hold th unique id as key and post as value using Object.entries
const retrievedPosts = [];
for (const [key, value] of Object.entries(response.data)) {
const post = {
id: key,
title: value.title,
content: value.content
};
// add allposts to the array here
retrievedPosts.push(post);
}
// update state
this.setState({ posts: retrievedPosts });
console.log(retrievedPosts);
});
}
handleChange = event => {
const [name, value] = [event.target.name, event.target.value];
// const value = event.target.value;
const { post } = this.state;
const newPost = {
...post,
[name]: value
};
this.setState({ post: newPost });
};
handleSubmit = event => {
event.preventDefault();
const { posts } = this.state;
// use this as a temporary id for post method
const postIndex = posts.length + 1;
const post = {
id: postIndex,
title: this.state.post.title,
content: this.state.post.content
};
axios
.post("firebaseURL/posts.json", post)
.then(response => {
const updatedPosts = [
...posts,
{ id: post.id, title: post.title, content: post.content }
];
// update state
this.setState({ posts: updatedPosts });
console.log(posts);
});
};
handleDelete = postId => {
event.preventDefault();
// get a copy of the posts
const posts = [...this.state.posts];
// in delete method use postId to create a unique url for the post to be deleted
axios
.delete(
"firebaseURL/posts/" + postId + ".json"
)
.then(response => {
//update state
this.setState({ posts: posts });
});
};
render() {
let posts = <p>No posts yet</p>;
if (this.state.posts !== null) {
posts = this.state.posts.map(post => {
return (
<Post
id={post.id}
key={post.id}
{...post}
delete={() => this.handleDelete(post.id)}
/>
);
});
}
return (
<React.Fragment>
{posts}
<form className="new-post-form" onSubmit={this.handleSubmit}>
<label>
Post title
<input
className="title-input"
type="text"
name="title"
onChange={this.handleChange}
/>
</label>
<label>
Post content
<textarea
className="content-input"
rows="7"
type="text"
name="content"
onChange={this.handleChange}
/>
</label>
<input className="submit-button" type="submit" value="submit" />
</form>
</React.Fragment>
);
}
}
The problem is my state is not updated after delete so although the post has been deleted from my database it is still in the DOM.
And more importantly if submit a new post cannot delete it after a get request or refresh being done. The reason is in post request the key will be created after the request is done and therefor I will not have the key to update state and DOM until after the next get request or refresh. And the id will be the temporary one which I assign during post method which cannot be used to delete a post.

Resources