Next.js how send 200 status to client in getInitialProps - reactjs

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 : []
}

Related

state used inside socket.on keeps its default value

const [allUsers, setUsers] = useState<ChatUser[]>([]);
const [currentUser, setCurrentUser] = useState<any>();
useEffect(() => {
console.log("all users : ", allUsers);
}, [allUsers]);
useEffect(() => {
const sessionID = localStorage.getItem("sessionID");
if (sessionID) {
socket.auth = { sessionID, username: "AOA_A", isAOA_A: true };
socket.connect();
} else {
socket.auth = { username: "AOA_A" };
socket.connect();
socket.on("connect error", (err) => {
if (err.message === "invalid username") {
console.log("error");
}
});
}
socket.on("session", ({ sessionID, userID }) => {
console.log("session");
// attach the session ID to the next reconnection attempts
socket.auth = { sessionID };
// store it in the localStorage
localStorage.setItem("sessionID", sessionID);
// save the ID of the user
socket.userID = userID;
});
socket.on("users", (data: ChatUser[]) => {
setUsers(() => {
const _users_: any[] = [];
data.forEach((user: ChatUser) => {
user.self = user.userID === socket.userID;
user.messages = [];
/* initReactiveProperties(user); */
_users_.push(user);
});
// put the current user first, and sort by username
_users_.sort((a, b) => {
if (a.self) return -1;
if (b.self) return 1;
if (a.username < b.username) return -1;
return a.username > b.username ? 1 : 0;
});
return _users_;
});
});
socket.on("private message", ({ message, from }) => {
console.log("setting messages", allUsers.length);
for (let i = 0; i < allUsers.length; i++) {
const user = allUsers[i];
if (user.userID === from) {
user.messages.push({
content: message.content,
from: from,
dateTime: "",
});
const _allUsers = [...allUsers];
_allUsers[currentUser.key] = currentUser!.user;
setUsers(_allUsers);
// if (user !== this.selectedUser) {
// user.hasNewMessages = true;
// }
break;
}
}
});
return () => {
socket.off("connect");
socket.off("disconnect");
socket.off("users");
socket.off("user connected");
socket.off("user disconnected");
socket.off("private message");
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
I want to setup a private messaging with MERN stack an socket.io .
At component rendering , it connect to server an the server will emit the list of all actif users , at the this point , the state is successfully updated , the first useEffect will log the updated state but when the socket.on("privated message") is called , when log the value of allUsers inside it is empty.

Upload Images in Loop React

I would like to send post request after every 10 count (ie. i = 10) (Slice 10 array of object from ImageObject and send it to backend). But i cant seem to update the state.
eg. if my ImageObject length === 500 , after every 10 loop , slice 10 array from ImageObject and send it to backend and so on untill ImageObject === 0
import { useState } from "react";
import axios from "axios";
import { v4 as uuidv4 } from "uuid";
import { S3Client } from "#aws-sdk/client-s3";
import { Upload } from "#aws-sdk/lib-storage";
type ImageType = {
name: string;
};
export default function App() {
const [mediaPath, setMediaPath] = useState<ImageType[]>([]);
const [file, setFile] = useState<File[]>([]);
const handleImagePaths = async (paths: ImageType[]) => {
try {
const options = {
headers: {
"Content-Type": "application/json"
}
};
await axios.post(
`/api/folders/uploads`,
{
media: paths
},
options
);
} catch (error) {
console.error(error);
}
};
const handleUpload = async () => {
for (var i = 0; i < file.length; i++) {
const imgFile = file[i];
// aws-sdk upload
const id = uuidv4();
const path = `folder/${imgFile.name}`;
let ImageObject: ImageType[] = [];
for (let j = 0; j < file.length; j++) {
ImageObject.push({
name: file[j].name
});
}
setMediaPath(ImageObject);
if (i % 10 === 0) {
const paths = ImageObject.slice(0, 10);
handleImagePaths(paths);
}
const target = {
Bucket: process.env.REACT_APP_HOST_AWS_BUCKET,
Key: path,
Body: imgFile,
ContentType: "image/jpeg"
};
const creds = {
accessKeyId: process.env.REACT_APP_HOST_AWS_ACCESS_KEY_ID || "",
secretAccessKey: process.env.REACT_APP_HOST_AWS_SECRET_ACCESS_KEY || ""
};
try {
const parallelUploads3 = new Upload({
client: new S3Client({
region: process.env.REACT_APP_HOST_AWS_DEFAULT_REGION || "",
credentials: creds
}),
leavePartsOnError: true,
partSize: 1024 * 1024 * 1000,
params: target
});
parallelUploads3.on("httpUploadProgress", (progress: any) => {});
await parallelUploads3.done();
} catch (e) {
console.error(e);
}
}
};
return (
<div className="App">
<h1>Send Post API After every 10 loop</h1>
</div>
);
}
Help !!
import { S3Client } from "#aws-sdk/client-s3";
import { Upload } from "#aws-sdk/lib-storage";
type ImageType = {
name: string;
} ;
export default function App() {
const [mediaPath, setMediaPath] = useState<ImageType[]>([]);
const [file, setFile] = useState<File[]>([]);
const handleImagePath = async (index: number, path: any, len: number) => {
if (index % 10 === 0 && index > 1) {
const paths = path.splice(0, 10);
try {
await axios.post(`/api/folders`, {
media: paths,
});
} catch (error) {
console.error(error)
}
} else if (index === len - 1) {
const paths = path;
try {
await axios.post(`/api/folders`, {
media: paths,
});
} catch (error) {
console.error(error)
}
}
};
const handleUpload = async () => {
for (var i = 0; i < file.length; i++) {
const imgFile = file[i];
const path = `folder/${imgFile.name}`;
mediaPath.push({
name: file[i].name,
});
handleImagePath(i, mediaPath, file.length);
const target = {
Bucket: process.env.REACT_APP_HOST_AWS_BUCKET,
Key: path,
Body: imgFile,
ContentType: "image/jpeg"
};
const creds = {
accessKeyId: process.env.REACT_APP_HOST_AWS_ACCESS_KEY_ID || "",
secretAccessKey: process.env.REACT_APP_HOST_AWS_SECRET_ACCESS_KEY || ""
};
try {
const parallelUploads3 = new Upload({
client: new S3Client({
region: process.env.REACT_APP_HOST_AWS_DEFAULT_REGION || "",
credentials: creds
}),
leavePartsOnError: true,
partSize: 1024 * 1024 * 1000,
params: target
});
parallelUploads3.on("httpUploadProgress", (progress: any) => {});
await parallelUploads3.done();
} catch (e) {
console.error(e);
}
}
};
return (
<div className="App">
<h1>Send Post API After every 10 loop</h1>
</div>
);
}

Chaining async/await calls in react

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)
}

React Function return nothing

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

My Request by token query is returning null

After the token has been stored in the Local Storage, I have a function where I can load the data of the currentStudent when the token is verified but the function is returning null.
this is my resolvers code
getCurrentStudent: async (
root,
{ studentId },
{ currentStudent, Student }
) => {
if (!currentStudent) {
return null;
}
const student = await Student.findOne({
studentId: currentStudent.studentId
});
return student;
}
and then i tried to make a context with the ApolloServer instance
const server = new ApolloServer({
typeDefs,
resolvers,
context: async ({ req }) => {
const token = req.headers["authorization"];
if (token !== null) {
try {
const currentStudent = await jwt.verify(token, process.env.SECRET);
req.currentStudent = currentStudent;
} catch (err) {
console.log(err);
}
}
}
});
this should verify my token and return the currentUser.
The function you pass to context should return a context object, or a Promise that will resolve to one:
context: async ({ req }) => {
const token = req.headers["authorization"];
let currentStudent;
if (token !== null) {
try {
const currentStudent = await jwt.verify(token, process.env.SECRET);
currentStudent = currentStudent;
} catch (err) {
console.log(err);
}
}
return {
currentStudent,
};
}
You can then utilize that context inside any of your resolvers, for example:
const resolvers = {
Query: {
currentStudent: (root, args, context) => {
return context.currentStudent;
}
}
};

Resources