remove the TMDB API - javascript

I am currently working with a clone of a streaming platform, it turns out that this clone has the TMDB API integrated and I want to remove it to store the objects returned by this api in a firebase database, but I am a little confused.
In my Firebase file, I have a promise that returns an array of objects and it looks like this:
export const getGamesDocument = () => {
return new Promise((resolve, reject) => {
const documents = [];
firestore
.collection("games")
.get()
.then((snapshot) => {
snapshot.forEach((doc) => {
const documentData = doc.data();
documentData.id = doc.id;
documents.push(documentData);
});
resolve(documents);
})
.catch((error) => {
reject(error);
});
});
};
So far everything is going well where I am getting confused is in this redux code since I have no knowledge of the subject:
export const fetchAdventureMoviesRequest = () => ({
type: moviesActionTypes.FETCH_ADVENTURE_MOVIES_REQUEST,
});
export const fetchAdventureMoviesSuccess = (adventureMovies, isPage) => ({
type: isPage
? moviesActionTypes.FETCH_ADVENTURE_MOVIES_SUCCESS
: moviesActionTypes.LOAD_MORE_ADVENTURE_MOVIES_SUCCESS,
payload: adventureMovies,
});
export const fetchAdventureMoviesFailure = error => ({
type: moviesActionTypes.FETCH_ADVENTURE_MOVIES_FAILURE,
payload: error,
});
export const fetchAdventureMoviesAsync = (fetchUrl, isPage) => {
return dispatch => {
dispatch(fetchAdventureMoviesRequest());
axios
.get(fetchUrl)
.then(res => {
const adventureMovies = res.data.results.map(el => ({
...el,
isFavourite: false,
}));
if (isPage) {
dispatch(fetchAdventureMoviesSuccess(adventureMovies, isPage));
} else dispatch(fetchAdventureMoviesSuccess(adventureMovies));
})
.catch(error => {
const errorMessage = error.message;
dispatch(fetchAdventureMoviesFailure(errorMessage));
});
};
};
I want to remove the array of objects that are obtained in the constant "adventureMovies" and replace it with the array of objects that I obtain in the aforementioned promise.

Related

How to pass return value from component to another one

I have a const that assembles a get (in another component) and returns me a verification code, this is: response.data.verifyCode
This component is called through a submit on another component.
I need to get this value in my another const, which is below:
export const sendCode = (id, username) => (dispatch) => {
dispatch({ some code here });
return registerAccount
.sendCode(id, username)
.then((response) => {
dispatch({ payload: response.data.verifyCode });
return response.data;
})
.catch(() => {
return null;
});
};
export const getCodeAndVerify = (id, userCode) => (dispatch) => {
dispatch({ some code here });
const getVerifyCode = // I need to get response.data.verifyCode from sendCode above
// I try to use
// const getVerifyCode = { verifyCode: sendCode() };
// but this returns [object object]
return registerAccount
.getCodeAndVerify(id, userCode, getVerifyCode)
.then(() => {
// some code here
})
.catch(() => {
// some code here
});
};
That is, I need to get the verifyCode from the return from the superior const and use it in the other const, but I'm not sure how to do that. Can someone help me?
Asynchronous actions (I'm assuming thunks) also receive a getState second argument after dispatch. Assuming there's a reducer to handle the verifyCode send code success, you can access the store and retrieve the verifyCode value in getCodeAndVerify.
export const sendCode = (id, username) => (dispatch) => {
dispatch({ some code here });
return registerAccount
.sendCode(id, username)
.then((response) => {
dispatch({
type: 'VERIFY_CODE_SUCCESS', // <-- action object needs type
payload: response.data.verifyCode,
});
return response.data;
})
.catch(() => {
return null;
});
};
export const getCodeAndVerify = (id, userCode) => async (dispatch, getState) => {
dispatch({ type: TYPES.PASS_CREATION_REQUESTED });
const getVerifyCode = getState().path.to.verifycode; // <-- retrieve from state
return registerAccount
.getCodeAndVerify(id, userCode, getVerifyCode)
.then(() => {
// some code here
})
.catch(() => {
// some code here
});
};

Handling multiple api calls with Promis.all and manipulating the data with react-redux

I am building an app with react/ redux for managing Collection of Electronic equipment (=donations).
In the first stage I need to make 2 api calls:
the first and the second are donations data and donors data (kept as different collections in mongodb) and then combine them. This info is shown in a donation route.
The action looks like this:
const basicUrl = 'http://localhost:8000/api';
export const requestDonor_DonationData = () => getDonationData (
`${basicUrl}/donor`,
`${basicUrl}/donation`
);
and the getDonationData func looks like this:
import {
REQUEST_ENTITIES_PENDING,
REQUEST_ENTITIES_SUCCES,
REQUEST_ENTITIES_FAILED
} from './constants';
export const getDonationData = (urlDonor, urlDonation) => (dispatch) => {
dispatch ( {type: REQUEST_ENTITIES_PENDING} );
Promise.all([
fetch(urlDonor).then(res => res.json()),
fetch(urlDonation).then(res => res.json())
]).then ( ([ donorResult, donationResult]) => donorResult.data.map( (e, i) => Object.assign(e, donationResult.data[i]) ) )
.then( mergedData => dispatch({type: REQUEST_ENTITIES_SUCCES, payload: mergedData }) )
.catch(error => dispatch({type: REQUEST_ENTITIES_FAILED, payload: error}) )
}
that works fine.
In the second stage, When a donation have been peeked up, it become an equipment (not the perfect word..) which means that now it is waiting for inspection. this info is shown in a equipment route.
the equipment data contain the donationId and status (different from the donation status).
Now I want to do something similar:
make 3 api calls (getting donor, donation, & equipment data)
merging the donor whit its donation data
filtering the merged
data with the donations that have been peeked up (status='DONE')
create a new json which takes the merged data and replace the ID and
status of donation with the ID and status of the equipment.
I tried
to do that with the first approach (just with Promise.all) but found
it very confusing working with multiple ".then" ...
this is what I tried :
the action-
export const requestEquipmentData = () => getEquipmentData (
[
`${basicUrl}/donor`,
`${basicUrl}/donation`,
`${basicUrl}/equipment`
]
);
export const getEquipmentData = (urls) => (dispatch) => {
dispatch ( {type: REQUEST_ENTITIES_PENDING} );
try {
const [ donorResult, donationResult, equipmentResult ] = Promise.all(urls.map(async function(url) {
const response = await fetch(url);
return response.json();
}));
const donationInfo = donorResult.data.map( (e, i) => Object.assign(e, donationResult.data[i]) );
const filteredDonation = donationInfo.filter(item =>item.status==='DONE');
const equipment = filteredDonation.map( (donation,i) => {
let obj = donation;
obj.id = equipmentResult.data[i].id;
obj.status = equipmentResult.data[i].status;
return obj;
})
dispatch({type: REQUEST_ENTITIES_SUCCES, payload: equipment });
} catch (error) {
dispatch({type: REQUEST_ENTITIES_FAILED, payload: error})
}
}
but I am doing somethig wrong, and that is the error:
type: "REQUEST_ENTITIES_FAILED", payload: TypeError: undefined is not a function
I would appreciate any help
The result of Promise.all() is a Promise that resolves to the array of results. It is not an array itself so you cannot destructure it like this.
You can use the same .then() approach that you used in your first example:
export const getEquipmentData = (urls) => (dispatch) => {
dispatch({ type: REQUEST_ENTITIES_PENDING });
Promise.all(urls.map(async function (url) {
const response = await fetch(url);
return response.json();
})).then(([donorResult, donationResult, equipmentResult]) => {
const donationInfo = donorResult.data.map((e, i) => Object.assign(e, donationResult.data[i]));
const filteredDonation = donationInfo.filter(item => item.status === 'DONE');
const equipment = filteredDonation.map((donation, i) => {
let obj = donation;
obj.id = equipmentResult.data[i].id;
obj.status = equipmentResult.data[i].status;
return obj;
})
dispatch({ type: REQUEST_ENTITIES_SUCCES, payload: equipment });
}).catch(error) {
dispatch({ type: REQUEST_ENTITIES_FAILED, payload: error })
}
}
Or you can use async/await syntax. Checkout this question for a generally discussion on resolving an array of Promises.
export const getEquipmentData = (urls) => async (dispatch) => {
dispatch ( {type: REQUEST_ENTITIES_PENDING} );
try {
const [ donorResult, donationResult, equipmentResult ] = await Promise.all(urls.map(async function(url) {
const response = await fetch(url);
return response.json();
}));
const donationInfo = donorResult.data.map( (e, i) => Object.assign(e, donationResult.data[i]) );
const filteredDonation = donationInfo.filter(item =>item.status==='DONE');
const equipment = filteredDonation.map( (donation,i) => {
let obj = donation;
obj.id = equipmentResult.data[i].id;
obj.status = equipmentResult.data[i].status;
return obj;
})
dispatch({type: REQUEST_ENTITIES_SUCCES, payload: equipment });
} catch (error) {
dispatch({type: REQUEST_ENTITIES_FAILED, payload: error})
}
}
In my opinion your general approach here is not good. You should read the guides on Normalizing State Shape. It seems like your APIs are returning normalized data and then your are "unnormalizing" it by combining data from multiple endpoints.

What is the better/correct way of using Promise.all with React-Redux-Thunk?

export const FETCH_DB_BEGIN = 'FETCH_DB_BEGIN'
export const FETCH_DB_SUCCESS = 'FETCH_DB_SUCCESS'
export const FETCH_DB_FAILURE = 'FETCH_DB_FAILURE'
export const fetchDatabase = () => {
return dispatch => {
const profile_url = 'localhost:5000/profiles'
const release_url = 'localhost:5000/releases'
const emp_url = 'localhost:5000/users'
let promises = []
let options = {
headers: header,
method: 'get',
mode: 'cors',
body: null,
}
dispatch(fetchDbBegin());
// run the script async. change state when it's done.
let profile_promise = new Promise((resolve, reject) => {
fetch(profile_url, options)
.then(res => res.json())
.then(resText => {
// Use Dispatch Here?
})
}).catch(err => {
console.log(err)
})
promises.push(profile_promise)
// run the script async. change state when it's done.
let release_promise = new Promise((resolve, reject) => {
fetch(release_url, options)
.then(res => res.json())
.then(resText => {
})
}).catch(err => {
console.log(err)
})
promises.push(release_promise)
// run the script async. change state when it's done.
let emp_promise = new Promise((resolve, reject) => {
fetch(emp_url, options)
.then(res => res.json())
.then(resText => {
})
}).catch(err => {
console.log(err)
})
promises.push(emp_promise)
Promise.all(promises).then(values => {
console.log(values)
})
}
}
export const fetchDbBegin = () => ({
type: FETCH_DB_BEGIN
});
export const fetchDbSuccess = (data) => ({
type: FETCH_DB_SUCCESS,
payload: { data }
});
export const fetchDbFailure = (err) => ({
type: FETCH_DB_FAILURE,
payload: { err }
});
I am in a process of refactoring a React class component to use Redux. It initially had all API calls inside the componentDidMount and it was so messy.
I am using redux-thunk to move this out from the class component.
The fetchDatabase in my databaseAction.js does everything that componentDidMount did in the class component.
Normally if it was a single API call, I would have just dispatched the fetchDbSuccess as the API call was done successfully. However, using Promise.All which takes three async API calls, I am not sure whether I should
create a separate action for each API call (fetchProfileSuccess, fetchReleaseSuccess, and fetchUserSuccess) and dispatch each one of them at the end of each Promise (the place where I put //Use Dispatch Here? in the code.
OR
Just dispatch single fetchDbSuccess when the Promise.all gets resolved.
If I choose to do 2, am I supposed to update all three states in my reducer?
Thanks
You should only dispatch and update state if you have code that cares about said state updates. For example, if you're just wanting to show a single spinner then have the spinner go away when fully completed, your user doesn't necessarily care about each atomic operation, so you don't need it reflected in state. If you have a UI that does show each, then you would want those extra dispatches.
By the way, your Promises look a bit overcomplicated. If you decide you don't need those extra state changes, you can simplify to this:
export const FETCH_DB_BEGIN = 'FETCH_DB_BEGIN'
export const FETCH_DB_SUCCESS = 'FETCH_DB_SUCCESS'
export const FETCH_DB_FAILURE = 'FETCH_DB_FAILURE'
export const fetchDatabase = () => {
return dispatch => {
dispatch(fetchDbBegin());
const urls = [
'http://localhost:5000/profiles',
'http://localhost:5000/releases',
'http://localhost:5000/users'
];
const options = {
headers: header,
method: 'get',
mode: 'cors',
body: null,
}
const fetchJson = url => fetch(url, options).then(res => res.json());
Promise.all(urls.map(fetchJson))
.then(([profile, release, employee]) => {
dispatch(fetchDbSuccess({ profile, release, employee }));
})
.catch(err => {
dispatch(fetchDbFailure(err));
});
}
}
export const fetchDbBegin = () => ({
type: FETCH_DB_BEGIN
});
export const fetchDbSuccess = (data) => ({
type: FETCH_DB_SUCCESS,
payload: { data }
});
export const fetchDbFailure = (err) => ({
type: FETCH_DB_FAILURE,
payload: { err }
});

Cannot access object/array in Javascript

I can console.log and see the array I created but as soon as I attempt to access it, I get undefined.
async componentDidMount() {
// fetch goal data for display
let response = await fetchWithToken("http://localhost:8080/api/getGoals");
let goalData = await response.json();
goalData = await goalData.filter(skill => skill.Skill === "CS_en");
// get info from people API with distinct list rather than every row
let people = new Set([]);
goalData
.filter(element => element.UpdatedBy !== null)
.forEach(element => {
people.add(element.UpdatedBy);
});
people = Array.from(people);
// call peopleAPI
const peopleObj = await peopleAPI(people);
console.log("peopleObj :", peopleObj);
console.log("peopleObj[0] :", peopleObj[0]);
}
Here is the peopleAPI where I'm calling another api and getting a list of user info.
const peopleAPI = people => {
return new Promise(function(resolve, reject) {
// get people API info
const peopleObj = [];
const apiPromises = [];
if (people) {
people.forEach(empid => {
const apiPromise = fetch(
`https://someApiCall/${empid}`
)
.then(res => res.json())
.then(res => {
peopleObj.push({
empid: res.id,
name: res.name.preferred ? res.name.preferred : res.name.full
});
})
.then(() => apiPromises.push(apiPromise));
});
// once all promises have been resolved, return a promise with the peopleObj
Promise.all(apiPromises).then(() => {
resolve(peopleObj);
});
}
});
};
export default peopleAPI;
Results of console.logs
Don't use push inside fetch.then, just return its value, and then push it to apiPromises`
const peopleAPI = people => {`
return new Promise(function(resolve, reject) {
// get people API info
const apiPromises = [];
if (people) {
people.forEach(empid => {
const apiPromise = fetch(`https://someApiCall/${empid}`)
.then(res => res.json())
.then(res => {
return {
empid: res.id,
name: res.name.preferred ? res.name.preferred : res.name.full
}
});
apiPromises.push(apiPromise)
});
Promise.all(apiPromises).then((data) => {
resolve(data);
});
}
});
};
export default peopleAPI;
Or even simpler and readable
const peopleAPI = people => {`
const apiPromises = people.map(empid => {
return fetch(`https://someApiCall/${empid}`)
.then(res => res.json())
.then(res => ({
empid: res.id,
name: res.name.preferred ? res.name.preferred : res.name.full
}));
});
return Promise.all(apiPromises)
};

How to use Fetch queries in a loop?

I make a request to the server via a map with different urls, then I set the data in State and use it for output. I want the requests to be consecutive but sometimes they do not work correctly and get bugs, how to write the code for normal data retrieval?
const urlList = ["countries", "states", "cities", "users"];
componentDidMount() {
urlList.map( (url, index) => {
return servicesAPI.getResourse(url).then( (body) => {
index !== 3 ? this.setState({
dataAPI : [...this.state.dataAPI, body] }) :
this.setState({
dataAPI : [...this.state.dataAPI, body],
loaded: true
})
})
})
export default class ServicesAPI {
_apiBase = `http://localhost:3001/`;
async getResourse(url) {
const res = await fetch(`${this._apiBase}${url}`);
if (!res.ok) {
throw new Error(`Could not fetch ${url}` +
`, received ${res.status}`)
}
return await res.json();
}
Use of Promise.all();
componentDidMount() {
const fetchPromises = [];
urlList.forEach( (url, index) => {
fetchPromises.push(servicesAPI.getResourse(url));
});
const allResourcesPromise = Promise.all(fetchPromises);
allResourcesPromise.then(data => {
// list with responses
}).catch(err => {
console.log(err.toString());
});
}
Sample example:
https://jsbin.com/vevufumano/1/edit?html,js,console,output
Also instead of then, where is possible, you can use async/await for more cleaner code.

Categories