What is different between asyncData and methods in nuxt js? - javascript

I currently used
asyncData for getting api data , but it can only used in pages ( not in components) .
But method can used in page and component .
These two method work the same ways and , so I am thinking to use methods for getting api data .
So I wonder is there any significant between asyncData and method ?
export default {
async asyncData ({ req }) {
let { data } = await axios.get(process.env.API_SERVER + `/v1/projects`)
return { items: data }
},
data () {
return {
items: null
}
},
methods: {
async getItems () {
let { data } = await axios.get(process.env.API_SERVER + `/v1/projects`)
this.items = data
}
}

There is a very big difference:
asyncData is a method which gets automatically called before the component gets initialized and therefore before the component data gets set.
Therefore you won't have access to this like in your methods.
asyncData is important for server side rendering where you want to fetch first your data before your component gets rendered with the fetched data. Nuxt will wait until the data got fetched before initializing and then rendering the component. Otherwise it would be rendered empty.
Methods are first available when the component is initialized.
You'll find more about asyncData here in the docs and there it's good described.

its like automatic promise
once you (ajax) request something then you get promise so you add then handler so when you get data your then code will be executed.
so ajax request will take some time so we are making that flow as async means continue the flow but when data received i need to execute some code which i have provided in then function
same goes with asyncData(its just wrapper for data with async capabilities) and async method what ever code you write inside will await for the given operation then when that operation is finished method will be executed.
its just like alert('hello') which await user for to click ok then continue the flow.
as well in server-side rendering it work same it will stop execution flow for a while for incoming data then again resumes it.
it more on depth with this js generators answer (if you are more interested): Difference between async/await and ES6 yield with generators

Related

React setState within Promise.all

I'm working on a project where we would like run multiple fetches in parallel to a very slow API. Ideally, we would like to populate our interface for the user as this data is received and do so in a summative manner. These requests may or may not resolve in the order that the API calls were made.
Most use cases of Promise.all with a setState involve setting state after all promises have resolved. However, what I'm looking to do demands setting state as a side effect within the child promises themselves, I believe.
So this is (simplified) what I am doing to achieve this:
const request = async (setState, endpoint) => {
const response = await fetch(endpoint);
const data = response.json();
setState(state => ({ ...state, ...data }))
}
// Called within React component as a side effect
const fetchAllData = (setState) => {
Promise.all(
[
request(setState, url_1),
request(setState, url_2),
request(setState, url_3)
]
)
}
Now, I'm running some testing and this does appear to work. I believe I should not be running into race conditions with the state because setState is being passed a function. However, I do wonder if I'm doing something dangerous with respect to React, updating state, and rendering.
Is there anything wrong with this picture?
There's nothing wrong with immediately updating state from each individual promise; this will work just fine. You might have a race condition if every request attempts to update the same bit of data, but as long as they write different parts of your state you should be fine (the state updater callback pattern is necessary though).
The only thing wrong with your code is the missing error handling, and that the Promise.all is currently a bit superfluous.

Is there a way to implement context on async function?

I'm writing a NodeJS based backend (cloud-function), and I got trouble in the situation as follow:
const context = createContext()
async main(event){
// I need to cache something here
context.set("I need this")
await someDeepFunction()
}
async function someDeepFunction() {
// ...... and got it in a very-very-deep logic
const val = context.get()
}
The main problem is that it's an async function, and when the NodeJS is handling the next request whiling waiting for the last, the context should switch automatically to ensure never lack the cache data of the first request.
I found a javascript project https://github.com/ealush/context, but it's not able to create context when use async.
Is it possible to implement and how?

React SetState Race Condition using Promise.all

componentDidMount() {
Promise.all([OfferCreationActions.resetOffer()]).then( () => {
OfferCreationActions.updateOfferCreation('viewOnly', true);
OfferCreationActions.updateOfferCreation('loadingOffer', true);
Promise.all([
OfferCreationActions.loadBarcodes(),
OfferCreationActions.loadBrandBarcodes(),
OfferCreationActions.loadBrands(),
OfferCreationActions.loadPayers(),
OfferCreationActions.loadSegments(),
OfferCreationActions.loadTactics(),
OfferCreationActions.loadStates(),
]).then(() => {
// let state settle before loading
setTimeout(() => {
OfferCreationActions.loadOffer(this.props.match.params.offerId);
}, 1500);
});
});
}
I'm working on a React app that needs to preload some data into state then load a larger object that references the preloaded data to map some fields. I've ran into a race condition in which some of the data from the promise chain is still being processed when I try to do the mapping. I added in the timeout yesterday but that doesn't feel like the best solution to me. I'm still fairly new to React and we are using Reflux as the store (if that makes a difference). Is there a better way to ensure all the data from the promise is currently being reflected in the state prior to making the call? Should I hook into componentShouldUpdate and check all of the fields individually?
There is a fundamental flaw with the way this is implemented! You are breaking the principle of uni directional data flow. Here are a few suggestions to fix it.
Do your side effect handling inside a seperate overarching function.
Handling promise race condition is a side effect(Something that is outside of React's UniFlow). So this is not a problem linked to "React". So as the first step onComponentDidMount delegate this race condition logic to a seperate action. Possibly do it inside "resetOfferOverall()" which is actually what is happening I guess.
Manage the promise inside the action and dispatch payloads to the store
In your code you are guaranteed that the "then" will be executed after the promise is resolved. Howerver the 2 calls to "updateOfferCreation" do not fall under this contract since it's outside the promise.all. May be they also need to come inside the massive promise.all section? Maybe they need to be completed before running the massive section. Just recheck this!
resetOfferOverall() {
Promise.all([OfferCreationActions.resetOffer()]).then( () => {
.then( () => {
// These are not guaranteed to be completed before the next "then" section!
OfferCreationActions.updateOfferCreation('viewOnly', true);
OfferCreationActions.updateOfferCreation('loadingOffer', true);
//*****************************************
Promise.all([
OfferCreationActions.loadBarcodes(),
OfferCreationActions.loadBrandBarcodes(),
OfferCreationActions.loadBrands(),
OfferCreationActions.loadPayers(),
OfferCreationActions.loadSegments(),
OfferCreationActions.loadTactics(),
OfferCreationActions.loadStates(),
]).then(() => {
OfferCreationActions.loadOffer(offerId);
});
});
}
If you want this sections to be completed before getting into that
massive promise all, change your code as follows.
async resetOfferOverall() {
Promise.all([OfferCreationActions.resetOffer()]).then( () => {
.then( () => {
await OfferCreationActions.updateOfferCreation('viewOnly', true);
await OfferCreationActions.updateOfferCreation('loadingOffer', true);
//await will stop code execution until the above async code is completed
Promise.all([
OfferCreationActions.loadBarcodes(),
OfferCreationActions.loadBrandBarcodes(),
OfferCreationActions.loadBrands(),
OfferCreationActions.loadPayers(),
OfferCreationActions.loadSegments(),
OfferCreationActions.loadTactics(),
OfferCreationActions.loadStates(),
]).then(() => {
//Now JS Guarantees that this call will not be called until everything above has been resolved!
OfferCreationActions.loadOffer(offerId);
});
});
}
Make sure that the actions you are waiting are returning a promise
Whatever pomises you wait on, if you do not actually return the relevant promise that is within the call itself, your code will not work properly.Let's consider the load barcodes action and Let's assume you use axios to fetch data.
loadBarcodes(){
// This "return" right here is vital to get your promises to behave properly
return axios.get('https://localhost:8080/api/barcodes/').then((response) =>{
//DISPATCH_TO_STORE
});
//If you did not return this promise this call will resolve immediately
}
On your component watch for the relevent Store. Show a loader until the payload is loaded to the store.
As you can see by relying on a store update to show the data we do not break the unidirectional data flow.

Mobx State Tree Flow. How to Know when it's done?

I am using mobx state tree and mobx for UI Stuff.
Now when I save something to db, after the request is done I want to update the ui(ie my mobx state).
I need to know when the flow is finished.
myFlow: flow(function* () {
// do stuff here.
}),
now I see that a promise is returned, so I thought of just doing
myFlow.then()
which works but I am wondering if this is the property way or if there is another way to do this(async/await? or some internal thing that flow has?)
a flow returns a promise, so any promise waiting mechanism works: .then, await, or yield inside another flow. If you want to render the state of the flow, take a look at mobxUtils.fromPromise(promise).case(....) of the mobx-utils package
Inside generator you can call some another action at the end.
In example below I call thisIsWhatYouNeed function. This function will be called when generator ends.
myFlow: flow(function* () {
try {
const response = yield fetch('your URL here');
const data = yield response.json()
// here you can call another action
self.thisIsWhatYouNeed(data);
} catch (error) {
console.log('error happens');
}
})
thisIsWhatYouNeed(data) {
// here you have your data and know that flow is finished
console.log('generator already finished');
}

Ajax call in React Starter Kit

I'm using React Starter Kit to create my first React app, and I'm struggling with Ajax calls. I saw that this Kit embeds a way to perform Ajax calls (which is by the way used internally for app routing):
import fetch from '../../core/fetch';
I've added this in my component, and then try to perform an Ajax call when the component loads. Here is my code:
componentDidMount() {
var moduleManager = 'https://my_domain.com/my_endpoint';
async function getModules (url) {
const response = await fetch(url);
const content = await response.json();
return content;
};
this.state.modulesList = getModules(moduleManager);
console.log(this.state.modulesList);
}
I'm also using the state value in my render function:
render() {
var rows = [];
for (var i = 0; i < this.state.modulesList.length; i++) {
rows.push(
<li>{this.state.modulesList[i]}<li/>
);
}
This code put together logs this in my console:
Promise {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined}
Then the Ajax call is performed (successfully) and my console is now showing this:
Promise
__proto__:Promise
[[PromiseStatus]]:"resolved"
[[PromiseValue]]:Array[16]
The desired behaviour is of course to update my view: when the ajax calls is performed, display one line per array member.
What am I missing?
Thanks
What I suggest doing:
constructor() {
...
// Bind your async function to your stateful component's class
this.getModules = this.getModules.bind(this);
}
async getModules(url) {
try {
// Perform the ajax call
const response = await fetch(url);
// Convert respone to json
const content = await response.json();
// Process your content (if needed)
...
// Call setState() here
this.setState({someContent: content});
} catch(e) {
console.error(e);
}
}
componentDidMount() {
this.getModules(`${URL}`);
}
You can't actually return the fetched/parsed data from an async function. According to this MDN link, async function returns a promise, and not the actual data you'd expect to get after parsing it.
What happened in your case, was that you were actually trying to receive a returned value from an async function, inside a regular(sync) function (componentDidMount). You can either do what I suggested, or use .then() to use setState after resolving and parsing the promise, in the actual componentDidMount function.
I suggest reading about async functions and Promise before continuing.
Best of luck!
Without testing your code, one problem is that you're incorrectly modifying state directly. That doesn't trigger a render and therefore your view is not updated. Try setState() instead, like so:
<li>{this.setState({modulesList[i]})}<li/>

Categories

Resources