How to perform a two callback functionality? - reactjs

I am using the cloudinary api with REACT/AXIOS and was wondering how I could pull data before the axios call and also after. My problem I am having is that if I use one callback I can only put the one or the other data. So is it possible to use two callbacks and if so how would you do so?
Or should I go about this a different way?
What I want is to pull the progression of the upload out and be able to store that value to the state. My only problem is that I am not sure of the correct way to do this? I need to do it inside the onUploadProgress fucntion.
Here is the code:
Function in component:
uploadImage(files) {
const image = files[0];
const cloudName = 'hyszj0vmt';
const url = `https://api.cloudinary.com/v1_1/${cloudName}/image/upload`;
const apiSecret = '***********';
const uploadPreset = '**************';
const timestamp = Date.now() / 1000;
const paramStr = `timestamp=${timestamp}&upload_preset=${uploadPreset}${apiSecret}`;
const signature = sha1(paramStr);
const params = {
api_key: '*******',
timestamp: timestamp,
upload_preset: uploadPreset,
signature: signature
};
APIManager.upload(url, image, params, (err, response) => {
if (err) {
console.log(`UPLOAD ERROR: ${err}`);
return;
}
const imageUrl = response['secure_url'];
let updatedProfile = Object.assign({}, this.state.updated);
updatedProfile['image'] = imageUrl;
this.setState({
updated: updatedProfile
});
});
}
APIManager function:
upload: (endpoint, file, params, callback) => {
let fd = new FormData();
fd.append('file', file);
Object.keys(params).forEach(key => {
fd.append(key, params[key]);
});
const config = {
headers: { 'X-Requested-With': 'XMLHttpRequest' },
onUploadProgress: progressEvent => {
const progress = Math.round(
progressEvent.loaded * 100.0 / progressEvent.total
);
console.log(progress + '%');
}
};
axios
.post(endpoint, fd, config)
.then(response => {
const { data } = response;
callback(null, data);
})
.catch(err => {
callback(err, null);
});
}
};

How about this?
upload: (endpoint, file, params, callback, callbackProgress) => {
...
const config = {
headers: { 'X-Requested-With': 'XMLHttpRequest' },
onUploadProgress: progressEvent => {
const progress = Math.round(
progressEvent.loaded * 100.0 / progressEvent.total
);
callbackProgress(progress);
}
};
...
});
Usage:
APIManager.upload(url, image, params, (err, response) => {
...
}, (progress) => {
console.log(progress);
});

Related

Redux Saga call api before token is set

I m trying to implements a react application with authentification using keycloak, all sounds good but when I refresh the page and there is fetching of an api, Saga perform the call before the token is set
there is my saga call
function* getAPI(action) {
const state = yield select();
try {
let response = yield call(
axiosRequest,
"get",
BaseURL,
`/foo/mini`,
{},
setAuthorizationBearer(state.auth.token),
{ sendToken: true },
"application/json"
);
yield put({ type: `${action.type}_SUCCESS`, payload: response, metadata: action.metadata })
} catch (e) {
yield put({ type: `${action.type}_ERROR`, payload: e })
}
}
and here is my axios request instance
import axios from "axios";
let authorizationBearer = null;
export const setAuthorizationBearer = token => {
authorizationBearer = token;
};
const instance = (
method,
baseURL = process.env.REACT_APP_ENDPOINT,
url,
data = null,
headers = null,
sendToken = true,
contentType
) => {
return new Promise((resolve, reject) => {
const p = {
sendToken: sendToken.sendToken,
data: {
...data,
},
};
const req = axios.create({
method,
baseURL,
url,
timeout: 30000,
headers: headers,
crossDomain: true,
});
headers = {};
if (p.sendToken && authorizationBearer) {
headers.Authorization = `Bearer ${authorizationBearer}`;
headers["Content-Type"] = contentType;
}
req({
method,
baseURL,
url,
data,
headers,
sendToken,
})
.then((payload) => {
if (payload) {
if (payload.status < 400) {
resolve(payload);
} else {
reject(payload);
}
} else {
reject(payload);
}
})
.catch((e) => {
if (axios.isCancel(e)) {
console.log("Request canceled", e.message);
} else {
// handle error
}
reject(e);
});
});
};
export default instance;
And finally i set my token on authentification with a dispatch
const dispatch = useDispatch()
<ReactKeycloakProvider onTokens={({token}) => dispatch(authUser(token))} authClient={Keycloak(config)}
initOptions={{
onLoad: 'login-required',
checkLoginIframe: false,
timeSkew: "0",
refreshToken: ""
}}
LoadingComponent={<div />}
>
....
</ReactKeycloakProvider>
Most probably the application content is being rendered before the onTokens is being executed. Try checking on the existence of the token in the store state before rendering anything (or show a loading screen).

Store geolocation coordinates as a const variable react

im a little stuck. Im trying to store the user coordinates from the componentDidMount in the handlesubmit as a const however whenever i try to I'll get an error. The error i'm getting is :
'position' is not defined no-undef.
Any way i could go about storing the position as a const so i could access it in the handlesubmit part?
Thanks
Code is below
componentDidMount() {
navigator.geolocation.getCurrentPosition(function(pos ) {
const { latitude, longitude } = pos.coords;
console.log(pos )
console.log(latitude)
console.log(longitude)
});
}
handleSubmit = (event) => {
const pName = document.querySelector('#pName') .value.trim();
const pCondition = document.querySelector('#pCondition') .value.trim();
const pDescription = document.querySelector('#pDescription') .value.trim();
const pLocation = position
console.log(pLocation )
const post = 'pName=' + encodeURIComponent(pName) + '&pCondition=' + encodeURIComponent(pCondition) + '&pDescription=' + encodeURIComponent(pDescription);
alert('A form was submitted: ' + data);
fetch('api url', {
method: 'POST',
mode: "no-cors",
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
// body: JSON.stringify(this.state)
body: post
}).then(function(response) {
console.log(response.text)
/*return response.json();*/
});
event.preventDefault();
}
Its simple
const getPosition = function () {
return new Promise(function (resolve, reject) {
navigator.geolocation.getCurrentPosition(resolve, reject);
});
}
getPosition()
.then(position => {
console.log(position);
sessionStorage.setItem('position', position);
)
.catch(error => {
console.error(error);
}
Use the variable position in the sessionStorage:
const data = sessionStorage.getItem('position');
Or you can use useState
const getPosition = function () {
return new Promise(function (resolve, reject) {
navigator.geolocation.getCurrentPosition(resolve, reject);
});
}
getPosition()
.then(position => {
console.log(position);
sessionStorage.setItem('position', position);
)
.catch(error => {
console.error(error);
}

How can I include response data to axios response?

I try to work with Axios interceptors. The problem I'm facing is that I can't show the response I got from the API with Axios or even if it does, it shows constant data.
axios.defaults.baseURL = 'https://localhost:5001/api/';
axios.defaults.withCredentials = true;
const responseBody = res => res.data;
axios.interceptors.response.use(async response => {
const pagination = response.headers["x-pagination"];
if (pagination) {
const parsed = JSON.parse(pagination);
let metaData = {
currentPage: parsed.currentPage,
pageSize: parsed.pageSize,
totalPages: parsed.totalPages,
totalCount: parsed.totalCount
};
response.data = {
metaData,
data: response.data //I want to change this data
// For example there is an endpoint named getAll and it returns all object
// Also there is a get endpoint and it returns a single object
// But the problem is axios always return getAll endpoint's data.
};
return response;
}
}, error => {
return Promise.reject(error);
});
This is my request object
const requests = {
get: (url, params) => axios.get(url, {params}).then(responseBody),
post: (url, data) => axios.post(url, data).then(responseBody),
put: (url, data) => axios.put(url, data).then(responseBody),
delete: (url) => axios.delete(url).then(responseBody),
postForm: (url, data) => axios.post(url, data, {
headers: {
'Content-Type': 'multipart/form-data'
}
}).then(responseBody),
putForm: (url, data) => axios.put(url, data, {
headers: {
'Content-Type': 'multipart/form-data'
}
}).then(responseBody)
};
and this is my API endpoints
const Endpoints = {
getAll: () => requests.get('Endpoint'),
get: (id) => requests.get(`Endpoint/${id}`),
create: (data) => requests.postForm('Endpoint', data),
update: (id, data) => requests.putForm(`Endpoint/${id}`, data),
delete: (id) => requests.delete(`Endpoint/${id}`),
}
What am I missing? Also, I use Redux Slice. If you want I can also send the redux code I write.
axios.interceptors.response.use(async response => {
const pagination = response.headers["x-pagination"];
if (pagination) {
const parsed = JSON.parse(pagination);
let metaData = {
currentPage: parsed.currentPage,
pageSize: parsed.pageSize,
totalPages: parsed.totalPages,
totalCount: parsed.totalCount
};
response.data = {
metaData,
data: response.data
};
return response;
}
return response; // problem solved after this
}, error => {
return Promise.reject(error);
});
The problem is I forget to return the response so that's why I always get the same data.

Axios.get not returning any data

I can not get the right info on my API.
i tried this and nothing comes back
const res = () => {
axios.get('https://api.scripture.api.bible/v1/bibles', {
headers: {
'api-key': '5b5d4503884b7a2515e8cee8f4b00746',
},
})
}
Your code works fine, but you are not doing anything with the response. axios.get() returns a Promise, so you need to handle it using .then()
const res = () => {
axios.get("https://api.scripture.api.bible/v1/bibles", {
headers: {
"api-key": "5b5d4503884b7a2515e8cee8f4b00746"
}
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
};
res();
or make an async function and use async await.
const res = async () => {
try {
const response = await axios.get("https://api.scripture.api.bible/v1/bibles", {
headers: {
"api-key": "5b5d4503884b7a2515e8cee8f4b00746"
}
});
console.log(response);
} catch (error) {
console.log(error);
}
};
res();
Instead of console.logging you can do anything, for example use a callback function:
const res = async (callback, errorCallback) => {
try {
const response = await axios.get("https://api.scripture.api.bible/v1/bibles", {
headers: {
"api-key": "5b5d4503884b7a2515e8cee8f4b00746"
}
});
callback(response);
} catch (error) {
errorCallback(error);
}
};
const onSuccess = result => {
const data = JSON.stringify(result);
alert(data)
};
const onError = error => {
alert(`Ops! An error occured: ${error}`);
};
res(onSuccess, onError);

Upload input form data and file/image Next js

I am trying to send form data life person name, email and image together using Next js. I used formdata for file upload and using react-hook-form for form input.
The problem is I couldn't receive the image/file in the Next api.
My codes are :
Onchange:
const handleImgChange = (e) => {
if (e.target.files && e.target.files[0]) {
const img = e.target.files[0];
setProfileImg(img);
}
};
to get form data from input.
const handleIChange = (e) => {
const value = e.target.value;
setContents((prevContnet) => {
return {
...prevContnet,
[e.target.name]: value,
};
});
};
On submit
const handleOnsubmlit = (e) => {
e.preventDefault();
if (profileImg.length > 0) {
const formData = { ...contents, profile_picture: profileImg };
updateUserSetting(formData);
} else {
updateUserSetting(contents);
}
};
updateUserSetting
async function updateUserSetting(formdata) {
try {
console.log("form datas", formdata);
dispatch({ type: "UPDATE_USER_SETTING_REQUEST" });
const { data } = await axios(
`${NEXT_URL}/api/updateusersetting`,
{
method: "PUT",
formdata,
"content-type": "multipart/form-data",
}
);
console.log("return data ", data[0]);
dispatch({ type: "UPDATE_USER_SETTING_SUCCESS", payload: data[0] });
} catch (error) {
dispatch({
type: "UPDATE_USER_SETTING_FAIL",
payload: error.response
});
}
}
API
import { IncomingForm } from "formidable";
export const config = {
api: {
bodyParser: false,
},
};
export default async (req, res) => {
if (req.method === "PUT") {
if (!req.headers.cookie) {
res.status(403).json({ message: "Not Authorized" });
return;
}
const { token } = cookie.parse(req.headers.cookie);
console.log("body is", req.body);
const formData = await new Promise((req, res) => {
const form = new IncomingForm();
form.parse(req, (err, fields, files) => {
if (err) {
next(err);
return;
}
res.writeHead(200, { "content-type": "multipart/form-data" });
res.json({ fields, files });
});
});
};
how can I put data together and send it to the desired API? Thanks in advance.
You can use the FormData interface to send files and other fields as a single JSONified string, or individual strings. Formidable will separate your fields and files in the callback, and you can process them individually.
Here's a working Codesandbox.
Output:

Resources