how to handle the async data in vue3 - javascript

I have the deman to fetch the server data and then process before rendering the page.
here is the code in my index.vue, in option api:
<template>
<div>{{userData.name}}</div>// đź’—'helloworld'
<div>{{testName}}</div>// ❌'undefined'
</template>
<script>
import {ref} from 'vue'
import axios from 'axios'
export default{
setup(){
const userData=ref([])
const testName = ref('')
oNmounted(async ()=>{
const res=await axios({url:'/myProfile',method:'get'})
})
userData.value=res.data.data //here I can get the async data after the Internet time travel.
//in other func to process the `userData` object which would be `[{name:'helloWorld',...}]
testName.value = userData.name
cosole.log(userData.name) //output `undefined`, but if i refer it in the template section, it works.
}
return {
userData,
testName,
}
}
</script>
I want to process the async data before it is rendered, how can I make sure that I could obtain the fetched data to use in the <script> section instead of <template> section?
And the userData I defined is a ref, in the beginnig of the async fetch, it is assumed to be undefined, but after the async axios, the userData is assinged to the latest target value I want, then why they won't be updated accordingly?
what am I missing in this fulfillment?

You defined userData as a ref (see https://vuejs.org/api/reactivity-core.html#ref)
const userData = ref([])
When you want to access the value of userData inside your code block, you need to use the property .value to points to the inner value.
If access is in the template tag, don't use the .value property.
So the corrected line would be :
testName.value = userData.value.name

Related

Struggling to get the data from useDocument to display with vue.js and Firestore

I'm trying to get a single record from Firestore to display in Vue.js. I'm using VueFire and the guide here.
<script setup>
import { initializeApp } from 'firebase/app'
import { getFirestore , doc } from "firebase/firestore";
import { useDocument } from 'vuefire'
const firebaseConfig = {...};
// Initialize Firebase
const firebaseApp = initializeApp(firebaseConfig);
const analytics = getAnalytics(firebaseApp);
const db = getFirestore(firebaseApp);
const place = useDocument(doc(db, "data", "key"));
console.log(place)
</script>
<template>
{{ place.title }}
</template>
The data logged is RefImpl {__v_isShallow: false, dep: undefined, __v_isRef: true, _rawValue : {title: 'I am a title', however when it gets to the template there is an error
Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'title')
Maybe try this.
...
const { data: place, pending } = useDocument(doc(db, "data", "key"));
</script>
<template>
<h1>Place</h1>
<template v-if="!pending">{{ place.title }}</template>
</template>
I'm just following what they the author of VueFire has posted here: https://github.com/vuejs/vuefire/blob/df3c235f226d4e4c821391bcce74a1c3a6134406/packages/nuxt/playground/pages/firestore-useDocument.vue
You can use the pending property to show the place once it has loaded.
You can also read about Subscription State here where they talk about destructuring. https://v3.vuefire.vuejs.org/guide/realtime-data.html#subscription-state
If anyone finds this because they need the data from useDocument() asynchronously, you can do something similar, based on Kyle's suggestion above (the Github post by the vueFire author):
const { data: place, promise } = useDocument(doc(db, 'data', 'key'))
promise.value.then((place) => {
// do something with place like console.table(place)
})
Even if you don't want to listen for changes, you still have to use the "subscription" method to get the data asynchronously. async/await doesn't work. This needs to be a lot clearer in the documentation IMHO.

location is not defined error in react + next js?

I am trying to send some text on basic of hosted url (where my build is deployed).but i am getting this error
ReferenceError: location is not defined
here is my code
https://codesandbox.io/s/laughing-mendel-pf54l?file=/pages/index.js
export const getStaticProps = async ({ preview = false, previewData = {} }) => {
return {
revalidate: 200,
props: {
//req.host
name: location.hostname == "www.google.com" ? "Hello" : "ccccc"
}
};
};
Can you show your imports, because it could be that you are importing router from 'next/client'
Assuming that you are using functional-based component
You need to import router as follows:
import {useRouter} from "next/router";
in your function body:
const router = useRouter();
getStaticProps() is executed at build time in Node.js, which has no location global object – Location is part of the browser API. Additionally, because the code is executed at build time, the URL is not yet known.
Change getStaticProps to getServerSideProps (see documentation). This will mean the function is called at runtime, separately for each request.
From the context object passed to getServerSideProps, pull out the Node.js http.IncomingMessage object.
On this object, look for the Host header.
export const getServerSideProps = async ({ req }) => {
return {
props: {
name: req.headers.host === "www.google.com" ? "Hello" : "ccccc"
}
};
};
Note:
I also changed == to ===, as it's generally advised to use the latter. The former can produce some unexpected results because of silent type conversions.
I also removed revalidate, as this is not applicable to getServerSideProps().

Unexpected error when querying for a field from Firebase

I am using React.js to query a field in a document from Firebase. However, when I try to get the data, I keep getting an error. The code, the collection on Firestore, and and the error message are below. How do I properly query specific fields of data without running into this error?
import React from 'react';
import styled from 'styled-components';
import { firestore } from '../../firebase/firebase.utils';
class Economics extends React.Component {
constructor() {
super();
this.state = {
name: firestore.collection('blog-categories').doc('8uVaHd22tT5oXSzpOOuj').get('name')
}
}
render() {
return (
<div>
hi
</div>
)
}
}
export default Economics;
I think this is proper reference for the API you are using.
When you enter parameter to get method API is expecting options object, so when you enter String "name" there you will get this error massage.
The method is asynchronous so you have to take value form DocumentSnapshot (reference) object returned as Promise which result of the method.
I hope it will help!
UPDATE: As requested I'm adding example:
Firestore has collection collection1 with document doc1 that has field field1 with value 'value1':
var Firestore = require('#google-cloud/firestore');
var db = new Firestore();
var docRef = db.collection("collection1").doc("doc1");
docRef.get().then(docSnap => {
console.log(docSnap.data().field1);
console.log(docSnap.get("field1"));
});
If you run this in node result is:
value1
value1

How to pass data from express's render to vue component?

Given an express route,
page.js
router.post('/results', (req, res, next) => {
output.terms = "hello"
output.results = [{"text": "hello world"}, {"text": "hello sunshine"}]
res.render("/myview",output)
})
The following works and shows the text.
myview.pug
extends ../layout.pug
block content
each result in results
span=result.text
But the following vue component doesn't. I receive TypeError: results is undefined
results-view.vue
<template lang="pug">
li(v-for='result in results')
span {{ result.text }}
</template>
<script>
export default {
...
}
</script>
myview.pug
extends ../layout.pug
block content
results-view
How do I pass the data from router to vue component?
You should probably think of some other solution. It does not make sense to pass data from route to component.
You can create an API endpoint that returns data and in Vue you can access it via request.
In the end, this worked. Might not be the best practice (I'm not sure, really) as warned by commenter serkan
results-view.vue
<template lang="pug">
li(v-for='result in results')
span {{ result.text }}
</template>
<script>
export default {
name: 'results-view',
props: ['results']
...
}
</script>
myview.pug
extends ../layout.pug
block content
results-view(results=results)
There are times when it makes sense to pass data from the router to your frontend component. No need to write an API and fetch that data in another roundtrip.
const customer = { id: '123', name: 'Jojo Sasa' }
res.render('customer/detail', { customer })
customer/detail.pug
// This will define customer as a global variable
script window.customer= !{JSON.stringify(customer)}
//The below code will run in the browser
script.
// This code will run in the browser
alert(`Customer is: ${cutomer.name}`)

Change value of field in reactjs component's state (with data obtained from firebase)

I simply want to fetch a string from a Firebase database and update the "eventName" field in my component, but I'm having trouble doing this.
My code so far:
import React from 'react';
import {ref} from '../Firebase';
class EventDisplay extends React.Component {
constructor () {
super();
this.state = {
eventName: "No event Selected."
};
}
render () {
return (<div>
<h1>Name of Event: {this.state.eventName}</h1>
<h1>Date and Time: Dummy Name</h1>
<h1>Event Description: Dummy Name</h1>
</div>);
}
changeEventName(str) {
this.setState({eventName: str});
}
componentWillMount() {
const events = ref.child('events/event1/Title');
var param;
events.on('value', (function(snapshot) {
param = snapshot.val();
console.log(snapshot.val());
changeEventName(param);
})
);
console.log(param);
}
}
export default EventDisplay;
However, changeEventName seems to be undefined where it is. Also "undefined" shows up in the console where I try to log param, but snapshot.val() has the desired string.
Thanks
changeEventName seems to be undefined where it is
Where you're calling changeEventName you need to prepend it with this.
this.changeEventName
Also since you're calling it inside of a callback you first need to bind the method in order to preserve the value of this. There're many ways you can do this, most common being:
Explicitly inside of a constructor:
this.changeEventName = this.changeEventName.bind(this)
Or using an arrow function:
events.on('value', ((snapshot) => { ... }));
Also "undefined" shows up in the console where I try to log param
That's because events.on is asynchronous, you need to move your console.log inside of the callback.
Try this.changeEventName when invoking the function; you need to do this because the function is available only within the context of the class.
Logging param returned undefined because events.on is an asynchronous function. What that means is that this function will go do whatever it was designed to do (fetch value) and only then execute the callback when its ready; param is only available in this callback method that you provided.

Categories