React websocket message coming before response - reactjs

I am having a case now with websockets.
I am using Promise to read response and message from socket. Afterwards I compare them and if they have the same id, it goes through.
However, most of the time socket message is arriving (fast) before response and as a result I cannot compare socket message with response id.
const init = {
get(...args) {
return request.get(...args);
},
post(...args) {
// return request.post(...args)
return new Promise((resolve, reject) => {
let response = {};
request
.post(...args)
.then((res) => {
console.log("RESPONSE====>", res);
response = res;
})
.catch((err) => reject(err));
webSocket.onmessage = (mes) => {
try {
// console.log(JSON.parse(mes.data))
let { correlation_id: socketId, status_code } = JSON.parse(mes.data);
console.log("MESSAGE====>", socketId);
if (socketId === response.message) {
resolve(response);
} else if (status_code > 300) {
reject({ status_code });
}
} catch (e) {
console.log(e);
}
};
// resolve(response)
});
}
export default init;
Above is my code for axios requests. If you know how to resolve it, kindly help here.

Related

Not able to get the response code in react js axios

Here is my common method for post:
export const post = (url: string, param: any) => {
const CancelToken = axios.CancelToken; // axios cancel request
const source = CancelToken.source();
post.prototype.source = source;
return axios.post(url, qs.stringify(param), { cancelToken:
source.token }).then((resp) => resp);
};
Here is my post method:
const postMyMethod = async () => {
await postMd(params)
.then((response: any) => {
console.log(response) // in response not getting status code
})
};
Below is the error handling code, how to get the response status code(ex: 200, 400...):
axios.interceptors.response.use(
function (response) {
if (response && response.data && response.data.Code && response.data.Message) {
message.error(response.data.Message);
response.data = null;
}
return response;
},
function (error) {
if (error.response && error.response.data && error.response.data.Code && error.response.data.Message) {
message.error(error.response.data.Message);
} else {
message.error('Unknown error, please check your network ~');
}
return error;
}
);
Finally if I do:
console.log(response)
Getting: Error: Request failed with status code 400
How to get the status code to do the if condition in the postMyMethod()?
I want to do like this in the postMyMethod(). How to achieve this?
if(response.status === 200){
// do something
}
if (respone.status === 400){
// do something
}
The error is because you are not using a catch() block in your postMyMethod function. You should add it so it will handle any error response. It will look something like this:
const postMyMethod = async () => {
await postMd(params)
.then((response) => {
console.log(response)
}).catch((err) => {
console.log(err.response.statuscode);
});
};
If response code 400 is something specific you want to handle differently in your function, your catch() block will be:
const postMyMethod = async () => {
await postMd(params)
.then((response) => {
console.log(response)
}).catch((err) => {
if (err.response.statuscode == 400) {
console.log(err);
} else {
console.log("something else");
}
});
};
You can read more about the catch() method here.
Finally got it:
.then((response: any) => {
console.log(response.response.status);
console.log(response.response.data);
})
or need to add below code under function error > if condition
return error.response;
Now getting the response status and failure data.

Waiting for POST request to finish before GET request starts (React/Node)

I have been trying for ages to fix this myself but I have given up. I am using React and Node to:
Send text from React to Node
Modify the text in Node
Send the modified text back to React
It all works fine if I click to start the POST request, wait a second, then click a different button to start the GET request, but I am trying to do it all from one command. My problem is that the GET request often finishes first, so my question is: How do I make sure the POST request finishes before the GET request starts.
I have tried this, but to no avail:
postReq = () => {
if(this.state.theUrl.length > 0) {
axios.post('http://localhost:5000/check', {
url: this.state.theUrl
}).then(function(response) {
console.log("Success")
}).catch(function(error) {
console.log(error)});
}
else {
return 1;
}
return "Finished"
}
getReq = () => {
axios.get('http://localhost:5000/check')
.then((getResponse) => {
this.setState({summaryParts: getResponse.data, postResponse: ""})});
};
callApi = async() => {
const result = await this.postReq();
this.getReq();
}
Try having await before get request.
callApi = async () => {
const result = await this.postReq();
await this.getReq();
};
Additionally, you need to update your postReq method as well, in order to await for the axios call returns with resolved promise. Otherwise, return Finished will be called before finishing the post request. (Therefore use async/await for postReq as well)
postReq = async () => {
if (this.state.theUrl.length > 0) {
/* await for the request to be finished */
await axios
.post("http://localhost:5000/check", {
url: this.state.theUrl,
})
.then(function (response) {
console.log("Success");
})
.catch(function (error) {
console.log(error);
});
} else {
return 1;
}
return "Finished";
};
add async and return
postReq = async () => {
if(this.state.theUrl.length > 0) {
return axios.post('http://localhost:5000/check', {
url: this.state.theUrl
}).then(function(response) {
....

Message Collector not worth

I'm making a support command: you type a command, the bot send you a message and then you reply to that message. I've used the awaitMessages function but it doesn't work.
case `support` : {
message.channel.send("What's your problem?");
let filter = m => m.author.id === message.author.id;
let msg = await message.channel.awaitMessages(filter, {maxMatches: 1});
message.channel.send("Your problem is: " + msg.first().content);
break;
}
To use .then() you need to return a Promise. This is a basic example of how you can use Promise:
const myFunction = () => {
return new Promise((resolve, reject) => {
if(taskIsSuccesFullyDone)
{
resolve(true); // Pass anything
}else{
reject('Something went wrong!');
}
});
}
myFunction().then(() => {
// Task is succesful completed.
// Do anything
})
.catch(error => console.log(error.message || error));
In your case, your code would look something like this:
function support_message() {
return new Promise((resolve, reject) => {
message.author.send(`Hello, <#${message.author.id}>, reply to this message explaining the problem you have.`)
.then(message => resolve(message))
.catch((error) => {
message.reply("I can't send you messages, be sure that you allow direct messages from unknown users to use this command.");
reject(error);
})
});
}
case `staff-support` : {
support_message().then(message => {
// We got the message object passed from the resolved Promise
// Do anything here
})
.catch((err) => {
// There was a problem!
// Do anything here.
});
break;
}

eventChannel emitter action is not taken from redux-saga

I have create saga watcher to connecting websocket and listen received data. const payload = yield take(socketChannel); is waiting for take received message, but it not all received from
emit({type: 'WEBSOCKET_MESSAGE_RECEIVED', message});
Can someone help to find the issue?
function createWebSocketConnection() {
return new Promise((resolve) => {
websocket.onOpen(() => {
makeRequests(websocket);
resolve(websocket);
});
websocket.connect(true);
});
}
function createSocketChannel(socket) {
return eventChannel((emit) => {
socket.onMessage((message) => {
if (message.path) {
console.log('Emitting received data...');
return emit({type: 'WEBSOCKET_MESSAGE_RECEIVED', message});
}
});
socket.onClose(() => {
emit(END);
});
socket.onError(() => {
emit(END);
});
const unsubscribe = () => {
socket.onMessage = null;
};
return unsubscribe;
});
}
function* listenForSocketMessages() {
let socket;
let socketChannel;
try {
socket = yield call(createWebSocketConnection);
socketChannel = yield call(createSocketChannel, socket);
// tell the application that we have a connection
yield dispatch(ActionCreators.wsClientOpened());
while (true) {
// wait for a message from the channel
const payload = yield take(socketChannel);
console.log('new payload');
// a message has been received, dispatch an action with the message payload
yield dispatch(createAction(payload.path, payload));
}
}
catch (error) {
// yield dispatch(ActionCreators.wsClientError());
}
finally {
if (yield cancelled()) {
// close the channel
socketChannel.close();
// close the WebSocket connection
socket.close();
}
else {
// yield dispatch(ActionCreators.wsClientError());
}
}
}
const createAction = (type: string, payload?: any) => ({
type,
payload,
});
export default function* watchConnectWebsocket() {
// starts the task in the background
const socketTask = yield fork(listenForSocketMessages);
// when DISCONNECT action is dispatched, we cancel the socket task
yield take(WsActionTypes.WEBSOCKET_CLOSED);
yield cancel(socketTask);
yield dispatch(ActionCreators.wsClientClosed());
}

reactJS how to stop it listening to ajax request

I have ajax call in componentdidmount. And and then setState inside the ajax promise.
The code is like this
componentDidMount(){
axios.post('mydomian.com/item/',this.state)
.then(function (response) {
const res = response.data
if (res.status === 'OK') {
this.setState({items :res.list})
}else{
console.log('can not load data', response)
}
}.bind(this))
}
componentWillUnmount(){
how to stop everything about axios?
}
This causes error 'can not setstate on an unmounted component', when I navigate to other route.
So I think what I should do is remove axios listener in the componentwillunmount. How to would you do it?
A very simple solution could be to set a flag on unmount and utilize it within the promise resolution, like so:
componentDidMount(){
axios.post('mydomian.com/item/',this.state)
.then(function (response) {
if (this.unmounted) return;
const res = response.data
if (res.status === 'OK') {
this.setState({items :res.list})
}else{
console.log('can not load data', response)
}
}.bind(this))
}
componentWillUnmount(){
this.unmounted = true;
}
I have find a great solution that has been defined by istarkov
const makeCancelable = (promise) => {
let hasCanceled_ = false;
const wrappedPromise = new Promise((resolve, reject) => {
promise.then((val) =>
hasCanceled_ ? reject({isCanceled: true}) : resolve(val)
);
promise.catch((error) =>
hasCanceled_ ? reject({isCanceled: true}) : reject(error)
);
});
return {
promise: wrappedPromise,
cancel() {
hasCanceled_ = true;
},
};
};
How to use:
const somePromise = new Promise(r => setTimeout(r, 1000));
const cancelable = makeCancelable(somePromise);
cancelable
.promise
.then(() => console.log('resolved'))
.catch(({isCanceled, ...error}) => console.log('isCanceled', isCanceled));
// Cancel promise
cancelable.cancel();
the solution has been found there.
My implementation.
Inside my function
const promiseShareByEmail = makeCancelable(this.props.requestShareByEmail(obj.email, obj.url));
promiseShareByEmail.promise.then(response => {
const res = response.data;
if (res.code != 0)
throw new Error(res.message);
this.setState({
message: {
text: TextMeasurements.en.common.success_share_test,
code: Constants.ALERT_CODE_SUCCESS
}
});
}).catch(err => {
if (err.isCanceled)
return;
this.setState({
message: {
text: err.message,
code: Constants.ALERT_CODE_ERROR
}
})
});
this.promiseShareByEmail = promiseShareByEmail;
this.props.requestShareByEmail(obj.email, obj.url) that function returns promise from axios.
when component will unmount cancel function should be invoked.
componentWillUnmount() {
this.promiseShareByEmail.cancel();
}
enjoy.

Resources