Render page when database contents changes - javascript

So suppose I have a page that displays all the user's posts. Right now when the user creates a post, it stores it into the database. But that new post will not appear unless I log out of the app and log back in. How can I make it so that the post will appear without having to logout?
const [Posts,setPosts] = useState([])
useEffect(()=>{
const fetchUserPosts = async () => {
const res = await client.get('/fetch-user-posts')
setPosts(res.data.posts)
}
fetchUserPosts()
},[])
And in the rendering I just took the Posts and map it to display its contents. I know this problem exists somewhere but I don't know what keywords to google. I have seen posts asking to use JQuery but I bet there is a simpler solution? Any pointers are appreciated.

Take the function of fetchUserPosts out of the useEffect like this:
const fetchUserPosts = async () => {
const res = await client.get('/fetch-user-posts')
setPosts(res.data.posts)
}
Now, useEffect will be like this:
useEffect(() => {
fetchUserPosts()
}, [])
Next, wherever you function of create user posts is, call fetchUserPosts() like this:
const addUserPosts = async () => {
// logic of adding new user post
if (success) {
await fetchUserPosts()
}
}

Related

Value (number) is different from the MongoDB to the react client async call

Problem:
An entire field of my MongoDB's collections' is not transmitted correctly from the db to the react client. For an exemple, the first element of this field is tweet_id: 1537466989966413825 in my DB. It becomes tweet_id: 1537466989966413800 when I fetch from my client.
My steps
I pull my data from the MongoDB using their App services' function like that:
exports = function(){
var collection = context.services.get("mongodb-atlas").db("meme_news").collection("news");
return collection.find({});
};
When I press the Run button of their built-in terminal, the correct data is displayed.
On my react's application, I perform the fetch like that:
useEffect(() => {
getData();
}, []);
const getData = async () => {
let getAllData = await user.functions.getAllData();
// all these data are wrong
let tweetId = getAllData
.map((ele) => {
return ele.tweet_id;
})
let tweetIdFirstEle = tweetId[0];
// this return 1537466989966413800
// It should return 1537466989966413825
};
Why is my async/await altering my Mongodb data? I have no idea what is going on here.

Query while iterating on array

I have Announcements and AnnouncementLikes schema. There is one schema for announcements and other one is for if user liked the specific announcement. My plan is sending announcements with like state to the user that made a request.
So on the below I tried to get like while iterating on announcement list.
const announcements = await AnnouncementModel.paginate(
{},
{
page,
limit,
lean: true
}
)
announcements.docs = announcements.docs.map((annonucement) => ({
...annonucement,
like: (async () => {
const result = await AnnouncementModel.findIfUserLiked(
annonucement.id,
req.userId
)
return result
})()
}))
It is inside of AnnouncementSchema I didnt want to copy all of the schema
static async findIfUserLiked(announcementId: string, userId: string) {
const foundAnnouncementLike = await AnnonucementLikeModel.findOne({
announcementId,
userId
})
return !!foundAnnouncementLike
}
I know that I cant get likes from immediatly invoked function because it returns a promise. So I have to stop iterate somehow and get like before sending to user. So i tried this solution but it didnt work as well
const fullOfPromises = announcements.docs.map((announcement) => announcement.like)
Promise.all(fullOfPromises).then(() => {
res.send(announcements)
})
I am new to mongoose and I dont know how to get user likes in the announcement list.
Thanks in advance

Component unable to fetch data from Firebase when navigating to it for the first time or coming back

Background
I'm building an app which displays a number of stores in the home screen. They are shown in a carousel which is filled up with information from a Firestore Collection and Firebase Storage. The user can navigate into each store by pressing on them. The Home Screen display works just fine every single time, but when navigating to one store components come back as undefined. This is the way I'm fetching the data:
export default function StoreDetailMain ({route}) {
const { storeId } = route.params
const [store, setStore] = useState()
useEffect(() => {
const fetchQuery = async () => {
const storeData = await firebase.firestore()
.collection('stores/')
.doc(storeId)
.get()
.then(documentSnapshot => {
console.log('Store exists: ', documentSnapshot.exists);
if (documentSnapshot.exists) {
console.log('Store data: ', documentSnapshot.data());
setStore(documentSnapshot.data())
console.log(documentSnapshot.data())
}
});
}
fetchQuery()
}, [storeId])
Then I'm rendering the information within tags as in <Text>{store.value}</Text>.
Problem
Navigating once to the store will always return a Component Exception: undefined is not an object (evaluating 'store.value'). However if I cut the "{store.value}" tags it works just fine. Then I can manually type them in again and they render perfectly. Once I go back to the Home Screen and try to go into another store I have to do it all again. Delete the calls for information within the return(), save the code, reload the app and type them in again.
What I have tried
Sometimes, not always, Expo will give me a warning about not being able to perform a React state update on an unmounted component. I thought this might be the problem so I gave it a go by altering my useEffect method:
export default function StoreDetailMain ({route}) {
const { storeId } = route.params
const [store, setStore] = useState()
useEffect(() => {
let mounted = true;
if(mounted){
const fetchQuery = async () => {
const storeData = await firebase.firestore()
.collection('stores/')
.doc(storeId)
.get()
.then(documentSnapshot => {
console.log('Store exists: ', documentSnapshot.exists);
if (documentSnapshot.exists) {
console.log('Store data: ', documentSnapshot.data());
setBar(documentSnapshot.data())
console.log(documentSnapshot.data())
}
});
}
fetchQuery()
}
return () => mounted = false;
}, [storeId])
This would not solve the issue nor provide any variation.
Question
Is this due to the unmounting/mounting of components? If so, wouldn't the useEffect method take care of it? If anyone could provide an explanation/solution it would be very much appreciated.
Thanks in advance.
Edit 1:
When the application fails to render the information, it doesn't print into the console the document snapshot. When it can render the data, it does log it. Thus the change in title.
try giving it a initial value
const [ store, setStore ] = useState({value: ''})
or render it conditionally
{ store?.value && <Text>{store.value}</Text> }
secondly, route.params is defined? When you switching screens, did u make sure u pass the params? Switching from stack navigator to tab navigator for example, may drop the params.

How to delay file import in React?

I am storing some keys in sessionStorage, these keys are a response from the login request. Once login is done, in componentDidMount() I'm making an API call to get user information. I have created api.js file with base URL and header, this header uses sessionStorage.getItem("keys") to make further user-specific API calls.
The issue is when the page loads for the first time the headers are null and I have to refresh again to get the header keys.
I have delayed the process using settimeout but still, the header is null for the first time.
Would something like this work for you?
const apijs = React.lazy(() => import('api.js'));
This will load the file only when you access apijs
You can make something like this.
<div >
<span>Hello {user?.email}</span>
</div>
If nothing has been registered by user, in header user will just see Hello.
const [keys, setKeys] = useState('')
useEffect(()=>{
const userLogin = () {
// login
const { data } = fetch('api')
const { keys } = data
sessionStorage.setItem("keys",keys)
setKeys(keys)
// so something
}
},[])
useEffect(()=>{
if(!keys) return
const getUserInfo = () => {
// call api to get user info
}
getUserInfo()
},[keys])

How to use synchronous and asynchronous functions inside onClick method in React

I have a react component with this state
const [name, setName] = useState('')
const [comment, setComment] = useState('')
const [notes, setNotes] = useState([])
this function handles the input elements to fill the order
const handleComments = () => {
setNotes([...notes, {
name,
comment
}])
setName('')
setComment('')
}
and this function sends the info to the server
const update = async () => {
const newNotes = notes.map(note => ({
name,
comment
}))
return updateNotesPromise(newNotes)
}
here I have a button that has to execute both functions
<Button onClick={} />
How can I create a function that is passed through the onClick method and executes handleComments in order to load the info on the DOM and then, once that info there, executes the update function and saves the order info into the DB ?
It looks like you're using functional components, so you can create a useEffect that makes an API put request whenever notes gets updated:
useEffect(()=> {
updateNotesPromise(notes);
},[notes])
I'm assuming updateNotesPromise is a function that makes your request call? It's also unclear why newNotes is being mapped from notes, or why update is async when it doesn't await anything. Your onClick would simply trigger handleNotes (I'm assuming that is your submit button).
Here's a way to handle the component updating and server communicating with error handling:
const onButtonClicked = useCallback(async (name, comment) => {
// cache the olds notes
const oldNotes = [...notes];
// the updated notes
const newNotes = [...notes, {
name,
comment
}];
// update the component and assume the DB save is successful
setNotes(newNotes);
try {
// update the data to DB
await updateNotesPromise(newNotes);
} catch(ex) {
// when something went wrong, roll back the notes to the previous state
setNotes(oldNotes);
}
}, [notes]);

Categories