I am trying to get Display Name getUserinfo() based on a User ID getList()
I have attempted
to use a variable to catch the data and feed to getList().
to use state variables to setState and pass data to getList(). but it seems State is asynchronous, so it failed
Problem: why my getUserinfo() cannot return a value for getList() to use ?
private getUserinfo(userid: number) {
var result;
let url;
url = `/_api/web/GetUserById(${userid})`;
const opt: ISPHttpClientOptions = {
headers: { "Content-Type": "application/json;odata=verbose" }
};
this.props.spHttpClient
.get(
this.props.context.pageContext.web.absoluteUrl + url,
SPHttpClient.configurations.v1,
opt
)
.then((response: SPHttpClientResponse) => {
response.json().then((json: any) => {
if (json.Title) {
let name = json.Title;
let email = json.Email;
let issiteadmin = json.IsSiteAdmin;
//debugger;
return name; // this has value but it returns nothing in another function I called
}
});
});
}
private getList() {
this.state.data.length = 0;
const qurl =
"/_api/web/lists/getbytitle('list')/items?$select=*&$orderby=Modified desc";
const opt: ISPHttpClientOptions = {
headers: { "Content-Type": "application/json;odata=verbose" }
};
this.props.spHttpClient
.get(
this.props.context.pageContext.web.absoluteUrl + qurl,
SPHttpClient.configurations.v1,
opt
)
.then((response: SPHttpClientResponse) => {
response.json().then((json: any) => {
for (let i = 0; i < json.value.length; i++) {
let authorid = json.value[i].AuthorId;
let editorid = json.value[i].Editorid;
let Authorname = this.getUserinfo(authorid);
let Editorname = this.getUserinfo(editorid);
debugger;
this.setState({
data: [
...this.state.data,
{
Authorname,
Editorname
}
]
});
}
});
});
}
Because you have not returned anything from getUserInfo, you had just called this.props.spHttpClient.get() without returning its value, for instance:
private getUserinfo(userid: number) {
...
return this.props.spHttpClient.get( ... )
.then((response: SPHttpClientResponse) => {
return response.json().then((json: any) => {
if (json.Title) {
let name = json.Title;
let email = json.Email;
let issiteadmin = json.IsSiteAdmin;
return name; // this has value but it returns nothing in another function I called
}
});
});
}
This way, when you call this.getUserinfo(authorid) you will get a promise and you can use its value as follows:
this.getUserinfo(authorid).then( name => {
// use its name
});
This is how you would write it using async/await which improves the readability
private async getUserinfo(userid: number) {
var result;
let url;
url = `/_api/web/GetUserById(${userid})`;
const opt: ISPHttpClientOptions = {
headers: { "Content-Type": "application/json;odata=verbose" }
};
const response: SPHttpClientResponse = await this.props.spHttpClient
.get(
this.props.context.pageContext.web.absoluteUrl + url,
SPHttpClient.configurations.v1,
opt
)
const json = await response.json();
if (json.Title) {
let name = json.Title;
let email = json.Email;
let issiteadmin = json.IsSiteAdmin;
//debugger;
return name; // this has value but it returns nothing in another function I called
}
}
You can aply the same style to getList
Related
I am using React functional component where I need to make 2 calls to different APIs. My code below hits both the fetcher functions and the result is printed inside. However, the value is not received when in return block. What is wrong here?
The passed URL in useSwr("URL", fectcher) was just a test for a unique key, but that doesn't help either
const fetchOrder = async (cookies, transactionId) => {
let options = {
...
};
let headerOptions = {
...
};
let res = await fetch(Constants.API_ENDPOINT + "/orderdetails", {
method: "POST",
body: JSON.stringify(options),
headers: headerOptions,
})
const json = await res.json();
// console.log(json) // This prints
return json;
};
const handleMatch = async (cookies, transactionId) => {
let optionsMatch = {
...
};
let headerOptionsMatch = {
...
};
let res = await fetch(Constants.API_ENDPOINT + "/match", {
method: "POST",
body: JSON.stringify(optionsMatch),
headers: headerOptionsMatch,
})
const json = await res.json();
// console.log(json) // This prints
return json;
};
const OrderDetails = () => {
const { data: matchData, error: matchError} = useSwr(
"/match",
handleMatch(cookies, transactionId)
);
const { data: orderData, error: orderError } = useSwr(
"/orderdetails",
fetchOrder(cookies, transactionId)
);
if (!match) return <div>Loading...</div>;
if (matchError) return <div>Error</div>;
if (!orderData) return <div>Loading...</div>;
if (orderError) return <div>Error</div>;
// Doesnt not proceed further from here as data is not received
return ()
}
I think the problem is from calling function in useSwr
they must be function to be returned
arrow function will do :
change this :
const { data: matchData, error: matchError} = useSwr(
"/match",
handleMatch(cookies, transactionId)
);
const { data: orderData, error: orderError } = useSwr(
"/orderdetails",
fetchOrder(cookies, transactionId)
);
to this :
const { data: matchData, error: matchError} = useSwr(
["/match",transactionId],
() => handleMatch(cookies, transactionId)
);
const { data: orderData, error: orderError } = useSwr(
["/orderdetails",transactionId],
() => fetchOrder(cookies, transactionId)
);
I have an application that can add NYT bestseller items to a database. Currently, users can add a bestseller to the db even if it already exists in the db. I want to be able to chain API calls such that if a user tries to save an item, the application first checks if that item is in the db, and only if it isn't proceed to save the item.
Here is my existing code:
const [currentInDb, setCurrentInDb] = useState(false);
interface bookInt {
title: string;
author: string;
}
const handleDbCheck = async(book: bookInt) => {
setCurrentInDb(false);
let targetObj = {
title: book.title,
author: book.author,
list: selectedCategory
}
try {
let url = baseURL + "/read-all";
axios.get(url).then((res) => {
for (let i = 0; i < res.data.length; i++){
let current = res.data[i]
if (current.title === targetObj.title && current.list === targetObj.list){
setCurrentInDb(true);
}
}
});
} catch (error) {
console.log(error);
}
}
const handleSaveBook = async (book: bookInt) => {
if (currentInDb){
console.log('handleSaveBook stopped early because item in db');
return;
}
try {
let newObj = {
title: book.title,
author: book.author,
list: selectedCategory,
};
let postURL = baseURL + "/create";
axios.post(postURL, newObj).then((response) => {
console.log('new item added');
});
} catch (error) {
console.log("error: ", error);
}
};
const handleCheckAndSave = async(book: bookInt): Promise<any> => {
await handleDbCheck(book)
.then(res => handleSaveBook(book))
}
Oddly, upon page reload, the first time I try to add an item to the db that is already there, I CAN add a duplicate. Then if I try to add it again, it correctly does not allow me to add it. Ideas?
There is no need to use .then in the async function. you can simply use await & chain your asynchornous requests.
const [currentInDb, setCurrentInDb] = useState(false);
interface bookInt {
title: string;
author: string;
}
const handleDbCheck = async(book: bookInt) => {
setCurrentInDb(false);
let targetObj = {
title: book.title,
author: book.author,
list: selectedCategory
}
try {
let url = baseURL + "/read-all";
const res = await axios.get(url)
for (let i = 0; i < res.data.length; i++){
let current = res.data[i]
if (current.title === targetObj.title && current.list === targetObj.list){
setCurrentInDb(true);
}
}
} catch (error) {
console.log(error);
}
}
const handleSaveBook = async (book: bookInt) => {
if (currentInDb){
console.log('handleSaveBook stopped early because item in db');
return;
}
try {
let newObj = {
title: book.title,
author: book.author,
list: selectedCategory,
};
let postURL = baseURL + "/create";
const response = await axios.post(postURL, newObj)
console.log(response)
} catch (error) {
console.log("error: ", error);
}
};
const handleCheckAndSave = async(book: bookInt): Promise<any> => {
await handleDbCheck(book)
await handleSaveBook(book)
}
I need to transfer status from the server to the client if I receive status 200 without content for getMainPage request. How can i do this?
I tried (example from google):
if (ctx.res) ctx.res.statusCode = 404;
return {notFound: true};
ctx.res always = undefined
/main page.ts/
IndexPage.getInitialProps = async (ctx: IExtendedAppContext): Promise<IPageProps> => {
const { reduxStore } = ctx;
const regionId = reduxStore.getState().regions.current?.id;
const cityId = reduxStore.getState().regions.current?.city;
const transaction = apm?.startTransaction('IndexPage');
const main: IMain = await reduxStore.dispatch(getMainPage({ region: regionId, city: cityId }, transaction));
const span = startSpan('fetchAlphabetList', transaction);
const alphabetList = await alphabetListService.fetch({ region: regionId, city: cityId })
.finally(() => endSpan(span));
endTransaction(transaction);
return { pageMeta: main.page_meta, alphabetList };
};
/with-redux-store.tsx/
export type Store = ReturnType<typeof getOrCreateStore>;
interface IProps {
reduxStore: Store;
initialReduxState: Store;
}
export interface IExtendedAppContext extends NextPageContext {
reduxStore: Store;
}
export interface IInitialProps extends AppContext {
ctx: IExtendedAppContext;
}
getMainPage request and all get requests uses that get method
public async get(entity: string, query: object, pathVariables: string[] | number[] = [], cookies: string = '') {
const queryURI = makeURIParams(query);
const key = makeQueryKey(entity, query, pathVariables);
try {
const localCopy = await this.getLocalCopy(key);
return this.handleResponse(localCopy);
} catch (error) {
console.log(this.getUrlAPI(entity, queryURI, pathVariables));
return this.fetch(this.getUrlAPI(entity, queryURI, pathVariables), {headers: {...this.getCookies(cookies)}})
.then(this._httpHandler).then(async (dataJSON: any) => {
try {
const { meta = {} } = dataJSON;
meta.requestDate = getCurrentTime();
const { expire, date } = meta;
if (expire <= date) {
await this.purgeStorageByKey(key);
return dataJSON;
}
if (expire !== 0) await this.setLocalCopy(key, JSON.stringify(dataJSON));
return dataJSON;
} catch (error) {
console.log(this.getUrlAPI(entity, queryURI, pathVariables), error);
return null;
}
}).then(this.handleResponse).catch((error: Error) => {
console.log(this.getUrlAPI(entity, queryURI, pathVariables), error);
return null;
});
}
}
/method where we can get request's status/
private _httpHandler(response: Response): Promise<IResponse | null> {
return new Promise(async (resolve, reject) => {
if ((response.status >= 200 && response.status < 300) || response.status === 403) {
try {
const json = await response.json();
resolve({ requestUrl: response.url, responseHeaders: response?.headers, ...json });
} catch (_) {
resolve(null);
}
} else {
reject(response.statusText);
}
});
}
so if it is async function and returns value, you can check status,
let mainResponseStatus = false;
if (main.status === 200) {
mainResponseStatus = true;
}
and then continue your code and return whatever you want but defense it in return
return {
somethingToReturn: mainResponseStatus ? returnWhatYouWant : []
}
First I had a typescript issue that my mocked data doesn't match to Response type. Then I tried to create mock data with Response constructor and got that error.
I have the following code
const HttpRequest = async function (
url: string,
options: RequestInit,
): Promise<Response> {
try {
return await fetch(url, options);
} catch (error) {
return null;
}
};
export default HttpRequest;
And following test:
const res = new Response();
window.fetch = jest.fn(
() => new Promise((resolve) => {
return resolve(res);
})
);
describe('HttpService', () => {
it('fetchWithFeedback', async () => {
const data = await HttpRequest('/api', { method: 'GET' });
expect(data).toEqual(res);
});
});
Change
const changeField = (field, id, value) => {
const newPropertyData = { ...propertyData };
if (newPropertyData.id === id) {
newPropertyData.field = value;
}
};
to
const changeField = (field, id, value) => {
if (propertyData.id === id) {
setPropertyData({ ...propertyData, [field]: value })
}
};
You're not updating your state in your onChange, so it's never able to update the value, which is still "".
I am getting a backend response to get the driver details using Axios and once after getting that I want to get the name, address of the driver. For that, I tried to set the value to a state variable but couldn't be able to assign, and also I have tried assigned the values to an array state variable and to access them later but I was unable to get a result
This is the code snippet:
getDriverInfo = async () => {
var session = sessionStorage.getItem("session");
var apiBaseUrl = "http://localhost:4000/api/";
// var self = this;
let det = [];
var payload = {
nic: session,
};
axios
.post(apiBaseUrl + "driverDetails", payload)
.then(async (response) => {
console.log(response.data.success);
if (response.data.code == 204) {
console.log("Driver Data retrieved successfull");
response.data.success.map((element) => {
det.push(element);
this.state.Ddetails.push(element);
});
console.log(det.length);
console.log(this.state.Ddetails[0].dln);
await this.setState({
fname: this.state.Ddetails[0].fName,
lname: this.state.Ddetails[0].lName,
});
} else {
console.log("Details does not exists");
alert("Details does not exist");
}
})
.catch(function (error) {
console.log(error);
});
console.log(det.length);
this.state.Ddetails.map((item) => {
console.log("Map");
console.log(item.dln);
});
console.log(this.state.Ddetails.dln);
};
Don't update state directly this is an anty pattern.
https://reactjs.org/docs/state-and-lifecycle.html#do-not-modify-state-directly
I have modified your code a little.
getDriverInfo = async () => {
var session = sessionStorage.getItem("session");
var apiBaseUrl = "http://localhost:4000/api/";
// var self = this;
let det = [];
var payload = {
nic: session,
};
axios
.post(apiBaseUrl + "driverDetails", payload)
.then(async (response) => {
console.log(response.data.success);
if (response.data.code == 204) {
console.log("Driver Data retrieved successfull");
response.data.success.map((element) => {
det.push(element);
//Don't use like this ==> this.state.Ddetails.push(element);
});
this.setState({Ddetails:det},()=>{
console.log(det.length);
console.log(this.state.Ddetails[0].dln);
this.setState(prevState=>{
console.log(det.length);
prevState.Ddetails.map((item) => {
console.log("Map");
console.log(item.dln);
});
console.log(prevState.Ddetails.dln);
return{
fname: prevState[0].fName,
lname: prevState[0].lName,
}
});
})
} else {
console.log("Details does not exists");
alert("Details does not exist");
}
})
.catch(function (error) {
console.log(error);
});
};
this.state = {
name: 'mickey',
lastName: 'mouse',
};
const display = () => {
// wont work
console.log(this.state.name, this.state.lastName);
}
function display() {
// will work
console.log(this.state.name, this.state.lastName);
}
As you can see arrow functions wont work with (this)