I'm doing a project that fetch different types of data from SWAPI API (people, planets, etc.) using react but I have an issue with multiple Ajax request.
The problem is when I quickly request from 2 different URL for example, 'species' and 'people', and my last request is 'species' but the load time of 'people' is longer, I will get 'people' instead.
What I want is to get the data of the last clicked request, if that make sense.
How do I achieve that? All the solution I found from Google is using jQuery.
Here's a slice of my code in src/app.js (root element) :
constructor(){
super();
this.state = {
searchfield: '',
data: [],
active: 'people'
}
}
componentDidMount() {
this.getData();
}
componentDidUpdate(prevProps, prevState) {
if(this.state.active !== prevState.active) {
this.getData();
}
}
getData = async function() {
console.log(this.state.active);
this.setState({ data: [] });
let resp = await fetch(`https://swapi.co/api/${this.state.active}/`);
let data = await resp.json();
let results = data.results;
if(data.next !== null) {
do {
let nextResp = await fetch(data.next);
data = await nextResp.json();
let nextResults = data.results
results.push(nextResults);
results = results.reduce(function (a, b) { return a.concat(b) }, []);
} while (data.next);
}
this.setState({ data: results});
}
categoryChange = (e) => {
this.setState({ active: e.target.getAttribute('data-category') });
}
render() {
return (
<Header searchChange={this.searchChange} categoryChange={this.categoryChange}/>
);
}
I made a gif of the problem here.
Sorry for the bad formatting, I'm writing this on my phone.
You have to store your requests somewhere and to abandon old ones by making only one request active. Something like:
getData = async function() {
console.log(this.state.active);
this.setState({ data: [] });
// my code starts here
if (this.controller) { controller.abort() }
this.controller = new AbortController();
var signal = controller.signal;
let resp = await fetch(`https://swapi.co/api/${this.state.active}/`, { signal });
let data = await resp.json();
let results = data.results;
if(data.next !== null) {
do {
let nextResp = await fetch(data.next);
data = await nextResp.json();
let nextResults = data.results
results.push(nextResults);
results = results.reduce(function (a, b) { return a.concat(b) }, []);
} while (data.next);
}
this.setState({ data: results});
}
Related
executing the fetch code in onNewScanResult multiplt time and hence updating the database accordingly................
initialization of qr scanner.........
this.html5QrcodeScanner = new Html5QrcodeScanner(
qrcodeRegionId,
config,
verbose
); ```Executing scanner when qrcode is scanned```
this.html5QrcodeScanner.render(
this.props.qrCodeSuccessCallback,
this.props.qrCodeErrorCallback
);
}
}
this is main qr code class........
class QrCode extends React.Component {
constructor() {
super();
this.state = {
decodedResults: [],
};
this.onNewScanResult = this.onNewScanResult.bind(this);
}
this is where the executing multiple time is happing.......
onNewScanResult(decodedText, decodedResult) {
`geting data from loacal storage as we saved data earlier in the process about acess level`
const qrRes = decodedText;
const obj = JSON.parse(qrRes);
const token = localStorage.getItem("user");
const userData = JSON.parse(token);
const username = userData[0].userId;
const accesslevel = userData[0].accessLevel;
const result = JSON.parse(qrRes);
const ele = result.ele_name;
const newdata = { ele, username, accesslevel };
const data = {
Element_detail: obj,
accessLevel: newdata.accesslevel,
};
const verifyUser = localStorage.getItem("accessLeveldetails");
const accessdetail = JSON.parse(verifyUser);
```checking is user is verified or not```......
`checking the acess level you can ignore the checking focus on fetch part`....
This particular part is we have to stop executing multiple time so database is only entered with one value
if (accessdetail.accessLevel === data.accessLevel) {
try { ``` this fetch is updating database with multiple entries```
fetch(
data.accessLevel === 20
? `/v0/all_elements_image`
: `/v0/${accessdetail.msg}`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(obj),
}
).then((res) => {
console.log(res);
if (!res) {
throw res;
}
return res.json();
});
} catch (error) {
console.log("Error:", error);
}
} else {
alert("WRONG USER");
}
}
}
how to consume from one api with another api.
var url_1 = 'https://dog.ceo/api/breeds/list/all';
fetch(url_1)
.then( response => response.json())
.then(data => {
const breeds = data.message;
var arr = [];
for (var b in breeds) {
arr.push({
breed : b,
subBreeds : [
breeds[b][0]
],
images : [{
url: ''
}]
})
}
I also have this other api, from where I extract the images of each breed of dog, but here you need the variable that would be the name of the dog's breed.
var url_2 = 'https://dog.ceo/api/breed/{breed_name}/images';
fetch(url_2)
.then( response => response.json())
.then(data => {
const images = data.message;
var arr_images = [];
for (var i in images) {
arr_images.push({
images : [{
url: images[i]
}]
})
}
So what I don't know, how can I join to send the name of the dog's breed to the second api to consume it?
And how can I join the arrangement of the images with the arrangement above?
it should be something like this
{ "breed": "Hound",
"subBreeds": [
"subBreedA",
"subBreedB",
"subBreedC"
],
"images":[
{"url":"http://some.url.com"},
{"url":"http://some.other.url"}
]
}
I hope I have been clear, thanks for your help, I will be very grateful.
I would split it up into separate functions so that you can focus on one part at a time. Then, combine them to get all of the data that you want. In this way, you can also re-use each function in case you want to use the data in a different way:
TS Playground
// dog.ceo API
async function fetchDogApiResult (apiPath) {
const response = await fetch(`https://dog.ceo/api/${apiPath}`);
if (!response.ok) throw new Error(`Response not OK (${response.status})`);
const data = await response.json();
if (data.status !== 'success') throw new Error('Response not successful');
return data.message;
}
async function fetchBreeds () {
return fetchDogApiResult('breeds/list/all');
}
async function fetchSubBreeds (breed) {
return fetchDogApiResult(`breed/${breed}/list`);
}
async function fetchImages (breed, subBreed) {
return fetchDogApiResult(`breed/${breed}${subBreed ? `/${subBreed}` : ''}/images`);
}
async function fetchDogData () {
const breeds = await fetchBreeds();
return Promise.all(Object.entries(breeds).map(async ([breed, subBreeds]) => ({
breed,
subBreeds,
images: (await fetchImages(breed)).map(url => ({url})),
})));
}
(async () => {
const dogData = await fetchDogData();
console.log(JSON.stringify(dogData));
})();
You can use async/await for call second api in second then of first api, after you get data from second api, you can use for loop for them. like this
var url_1 = 'https://dog.ceo/api/breeds/list/all';
fetch(url_1)
.then( response => response.json())
.then(async data => {
const breeds = data.message;
const resUrl2 = await fetch(url_2)
const dataUrl2 = await resUrl2.json()
var arr = [];
for (var b in breeds) {
arr.push({
breed : b,
subBreeds : [
breeds[b][0]
],
images : [{
url: ''
}]
})
}
const images = dataUrl2.message;
var arr_images = [];
for (var i in images) {
arr_images.push({
images : [{
url: images[i]
}]
})
}
})
I'm using #tensorflow-models/knn-classifier to classify my models and #tensorflow-models/mobilenet to study new models.
methods: {
async init() {
// load the load mobilenet and create a KnnClassifier
this.classifier = knnClassifier.create();
this.mobilenet = await mobilenetModule.load();
},
async addExample() {
let selected = document.getElementById("options");
this.class = selected.options[selected.selectedIndex].value;
const img = tf.browser.fromPixels(this.$children[0].webcam.webcamElement);
const logits = this.mobilenet.infer(img, "conv_preds");
this.classifier.addExample(logits, parseInt(this.class));
}
How can I save to localStorage my examples, which I added to the classifier and then load them in init() method? Because currently, I'm losing all my models after the page refresh.
Sorry maybe for the wrong terminology, I'm so new in Tensorflow js.
So, after small research I managed to save and load data with the next methods:
async toDatasetObject(dataset) {
const result = await Promise.all(
Object.entries(dataset).map(async ([classId, value]) => {
const data = await value.data();
return {
label: Number(classId),
data: Array.from(data),
shape: value.shape
};
})
);
return result;
},
fromDatasetObject(datasetObject) {
return Object.entries(datasetObject).reduce(
(result, [indexString, { data, shape }]) => {
const tensor = tf.tensor2d(data, shape);
const index = Number(indexString);
result[index] = tensor;
return result;
},
{}
);
},
And then I just load it:
this.classifier.setClassifierDataset(
this.fromDatasetObject(JSON.parse(localStorage.getItem("my-data")))
);
Im kind of an Beginner within Vuejs. Im Creating a Site which shows content that is loaded from the Backend into the Frontend. Therfore, I use Axios to connect to the API with this code:
contentList: [],
};
const mutations = {
setContent (state) {
axios
.get("http://backendapi/content")
.then(res => {
const data = res.data;
for (let key in data) {
const object = data[key];
state.contentList.push(object)
}
});
}
};
const actions = {
initContent: ({commit}) =>{
commit('setContent');
}
};
and on my Page i load the Contentlist when mounted:
mounted() {
this.$store.dispatch('initContent');
this.content = this.$store.getters.contentList
}
But the Problem is, every Time i go to another Page and back to this Page, the Content is loaded again into the contentList and everithing ist doubled.
Can someone explain, how to write this in "good Code" and avoiding loading everything double?
Thank you
You can check if already have the content on your list before making the request.
setContent (state) {
if (state.contentList.length == 0){
axios
.get("http://backendapi/content")
.then(res => {
const data = res.data;
for (let key in data) {
const object = data[key];
state.contentList.push(object)
}
});
}
}
or if you want to update each time just make sure the variable is reset each time.
axios
.get("http://backendapi/content")
.then(res => {
const data = res.data;
let contentList = [];
for (let key in data) {
const object = data[key];
contentList.push(object);
}
state.contentList = contentList;
});
Just check whether the content is already loaded before doing an axis call. Also the action is meant to execute the axios call:
const mutations = {
setContent (state, data) {
state.contentList = data
}
};
const actions = {
async initContent: ({commit, state}) =>{
if (state.contentList.length === 0) {
try {
let result = []
let response = await axios.get("http://backendapi/content")
for (let key in response.data) {
result.push(response.data[key])
}
commit('setContent', result);
} catch (error) {
// something went wrong
}
}
}
};
I am getting data from the backend to display it in the font like this
componentDidMount() {
const response = this.props.store.privateImputationData;
console.log(response);
}
It displays null in the console, now if i do a setTimeout it works!
componentDidMount() {
setTimeOut(() => {
const response = this.props.store.privateImputationData;
console.log(response);
}, 500);
}
This how i m getting data from my store:
#computed get ImputationData() {
return this.privateImputationData || {};
}
loadImputation = (diplayedImputations) => {
HttpClient.postJSON(this.apiDataUrl, diplayedImputations).then((result) => {
this.privateImputationData = result;
this.loadAdditionalData();
});
}
How can i do it without setTimeout?
You can use the state object: State and Lifecycle. Whenever the state changes, whatever component uses it, get's updated too.
this.state = {privateImputationData: null} //or some default
So in your code:
#computed get ImputationData() {
return this.privateImputationData || {};
}
loadImputation = (diplayedImputations) => {
HttpClient.postJSON(this.apiDataUrl, diplayedImputations).then((result) => {
this.setState({privateImputationData: result});
this.loadAdditionalData();
});
}
To use the value:
this.state.privateImputationData;