Get undefined property error after declare varible in async created Nuxtjs - javascript

I'm working with nuxtjs in ssr mode, i'm having this function to setup data for my component. I keep getting
Cannot read property 'data' of undefined. But some how myInfo state still get the data. Can someone explain why this happend. Here is my code
async created() {
this.isLoading = true;
await this.initData();
},
methods: {
async initData() {
let myInfo;
if (this.param) {
if (this.$store.userLogin) {
myInfo= await this.$repositories.api1(this.param);
} else {
myInfo= await this.$repositories.api2(this.param);
}
}
this.myInfo= myInfo.data;
}
}
I'm trying to create a function to setup data for component in Nuxtjs, using async created

Related

Javascript global variable with async/await is set, but later undefined

I'm setting up a mongoDB endpoint with NodeJS. Implementing this backend
I seem to have a problem with the code where the function static async injectDB sets a global variable let restaurants which another function static async getRestaurants accesses, but then it turned into undefined
import mongodb from "mongodb"
const ObjectId = mongodb.ObjectID
let restaurants
export default class RestaurantsDAO {|
static async injectDB(conn) {
if (restaurants) {
return
}
try {
restaurants = await conn.db(process.env.RESTREVIEWS_NS).collection("restaurants")
} catch (e) {
console.error(
`Unable to establish a collection handle in restaurantsDAO: ${e}`,
)
}
}
static async getRestaurants({
filters = null,
page = 0,
restaurantsPerPage = 20,
} = {}) {
console.log(restaurants) // undefined
...
getRestaurants is of course called at a much later point than injectDB, if I console.log(restaurants) in that function, it writes out its values. But its undefined when the other function is called. Why is that?
The injectDB function is called at server start, while the getRestaurants is called when someone acceesses the endpoint.
An alternative solution is to open the connection to DB in the getRestaurants function, is that best practice?
See full code for restaurantsDAO.js
Be aware that you cannot know if the await code has finished unless you check for it. It can really help to put console.logs everywhere! See this example:
export default class RestaurantsDAO {
static restaurants
static async injectDB(conn) {
if (RestaurantsDAO.restaurants) {
return
}
try {
console.log("start loading")
RestaurantsDAO.restaurants = await conn.db(process.env.RESTREVIEWS_NS).collection("restaurants")
console.log("finished loading restaurants!")
} catch (e) {
console.error(
`Unable to establish a collection handle in restaurantsDAO: ${e}`,
)
}
}
static showRestaurants() {
if (RestaurantsDAO.restaurants) {
console.log("restaurants are loaded")
} else {
console.log("restaurants not yet loaded")
}
}
}
So if you call injectDB anywhere else in your code, that doesn't guarantee that restaurants is filled right away.
import RestaurantsDAO from "./restaurantsdao.js"
RestaurantsDAO.injectDB(..) // console: "start loading"
RestaurantsDAO.showRestaurants() // console: "restaurants not yet loaded"
// console: "finished loading" (because await has finished)
BTW I think it makes more sense if you make the restaurants variable part of the class, instead of defining it outside of the class on the module.

Apollo-client useLazyQuery returning undefined on refetch

I have a subcomponent Viewer that uses a refetch function passed down to its parent Homescreen.
The lazyQuery in homescreen is structured as follows:
const [getById, {loading, error, data, refetch}] = useLazyQuery(GET_BY_ID);
This will get an object from my mongoDB by its id, and when I need to call it again and reload data into my custom activeObject variable, I use the follow function:
const refetchObjects= async () => {
const {loading, error, data } = await refetch();
if (error) { console.log(error);}
if (data) {
activeObject = data.getRegionById;
}
}
However, sometimes the return object of await refetch(); is undefined and I'm not sure why.

Why my first load data axios is return 404 Vue Js?

so guys I've tried to fetch data and show it inside my component. But the problem is, fetching data got 404 or data not show for the first load.. but when I try to reload again data is shown as should be. And one thing.. the data was success upload to the server even the response status 404 as I said
By the way guys this is my component.js
getApi() {
return api.get("/routeName")
}
this is my Store
async fetchApi({ commit }) {
try {
let {
data: { data }
} = await component.getApi()
commit("SET_API", data)
} catch (error) {
return Promise.reject(error)
}
}
and this is how I call fetchApi from a store inside my component
async created() {
await this.getApi()
}
methods: {
async getDraft() {
try {
await this.$store.dispatch("component/fetchApi")
this.scrollToTop()
} catch (error) {
error
}
}
}
I assume you access VUEX state data in <template> tag (I cannot comment to get more information.)
If I right, the problem is compoent not watch VUEX state when data null while you access.
If you render when VUEX state data is null, when data update while you call fetchDraft in yours store. In component not track your VUEX. I don't know why it happen in low level.
In my case, I need to use setInterval to load Vuex state to local data in component. And use it instead of access direct to vuex.
ex.
created() {
this.intervalUpdate = setInterval(() => {
this.updateData();
}, 1000);
},
destroyed() {
clearInterval(this.intervalUpdate);
},
methods: {
async updateData() {
this.draftData = await this.$store.dispatch("review/fetchDraft");
}
}
It's not the best solution. But its help me to solve problem that component

await/async axios call being called before response from previous call is done

I have a React component that calls an async function in componentDidUpdate. Inside that function, I have an array of items that I call Promise.all on. There is one condition where an axios call is made depending on what gets returned from a previous axios call. The problem I am having is that the axios call is made before the results from the previous axios call is finished, and I am not sure why that is happening.
Here is my code:
class Test extends Component {
this.state = {
experiments: []
}
async componentDidMount() {
await this.getExperiments(); // function to fetch experiments from a db
}
async componentDidUpdate() {
if (condition) {
await myFunction()
}
}
myFunction = async () => {
try {
const { experiments } = this.state;
const results = await Promise.all(experiments.map(async experiment => {
const firstAxiosCall = await axios.get(someUrl);
const secondAxiosCall = await axios.get(anotherUrl)
const { data } = secondAxiosCall; // THIS IS WHERE BUG OCCURS
if (data.length === 0) { // For one experiment, this is not empty, but it still goes into the if statement.
await axios.post(thirdUrl)
}
}));
} catch (e) {
console.log('ERROR', e);
}
}
}
I know that this is a bug because the axios call inside the if statement is called and I get a db error on my backend saying that nothing was passed in. I want the data from the second axios call to return first before proceeding the if statement. Is there something that I am doing wrong?
I hope this is enough information!
Thank you all!
I'd suggest you to use something like so:
myFunction = async () => {
await axios.all([
axios.get('http://someurl.com'),
axios.get('http://anotherurl.com')
])
.then(axios.spread((someUrlRest, anotherUrlRes) => {
// do something with both responses
});
}

this is undefined outside from constructor

I created an Express REST API using Dependency Injection with Inversify. I have a basic controller class
import { Request, Response, NextFunction } from 'express';
import { injectable, inject } from 'inversify';
import { IUserController } from './IUserController';
import { AppEntity } from '../../enterpriseBusinessRules/entities/AppEntity';
import { UserEntity } from '../../enterpriseBusinessRules/entities/UserEntity';
import { GroupEntity } from '../../enterpriseBusinessRules/entities/GroupEntity';
import { IUserUseCases } from '../../applicationBusinessRules/useCases/IUserUseCases';
import { IOCTypes } from '../../iOC/IOCTypes';
#injectable()
export class UserController implements IUserController {
public userUseCases: IUserUseCases;
constructor(#inject(IOCTypes.IUserUseCases) userUseCases: IUserUseCases) {
this.userUseCases = userUseCases;
}
public async fetchUsers(request: Request, response: Response, next: NextFunction): Promise<void>{
try {
const users: UserEntity[] = await this.userUseCases.fetchUsers(request);
response.status(200).json({
message: 'Users were fetched.',
users,
});
} catch (error) {
next(error);
}
}
}
Whenever I request the route /users the function fetchUsers gets executed. Unforunately my API crashes and throws this error
RangeError [ERR_HTTP_INVALID_STATUS_CODE]: Invalid status code:
undefined
I debugged and found this error
TypeError: Cannot read property 'userUseCases' of undefined
Within the constructor of the class this is set and works fine. Within the fetchUsers function this is undefined. How can I fix this? Because I have to use this to get access to my userUseCases variable.
Edit: Thanks to Adam Kosmalas comment I was able to fix it by binding the function within the constructor
this.fetchUsers = this.fetchUsers.bind(this)
but I don't know if this is the best solution. Then I would have to bind every function in every class within its constructor...
Any other ideas?
Another options is to use arrow functions for method declarations. This way you don't need to explicitly bind this:
public fetchUsers = async (request: Request, response: Response, next: NextFunction): Promise<void> => {
try {
const users: UserEntity[] = await this.userUseCases.fetchUsers(request);
response.status(200).json({
message: 'Users were fetched.',
users,
});
} catch (error) {
next(error);
}
}
Inside the constructor bind "this" to your function using bind(this) this will make sure It will execute the function in context of "this" of the class.
constructor(#inject(IOCTypes.IUserUseCases) userUseCases: IUserUseCases) {
this.userUseCases = userUseCases;
this.fetchUsers = this.fetchUsers.bind(this)
}
It was not working because your function was executing somewhere else thus it was getting 'this' from there
If you don't want to bind and properties are public then you can directly access if from outside of the service like.
const users: UserEntity[] = await this.nameOfTheImportedService.userUseCases.fetchUsers(request);

Categories