axios__WEBPACK_IMPORTED_MODULE_0___default.a[method] is not a function - reactjs

I'm getting above error when I make a request to backend. I have similar code on another project, there is no issue. but here it's causing problems
my code:
import axios from 'axios';
export default function apiCall(method, path, data) {
console.log(method, url, data);
return new Promise((resolve, reject) => {
return axios[method](path, data)
.then(res => {
return resolve(res.data);
})
.catch((err) => {
console.log(err)
reject(err)
});
});
}
api call function
apiCall('POST', `${process.env.REACT_APP_BASE_URL}/`, {standard, subject, totalMarks, totalQuestions} )
.then(data =>{
console.log(data);
})
.catch(err=>{
console.log(err);
return this.props.addError(err.message)
});

Pay attention to the fact that objects in javascript are case sensitive, therefore, accessing obj['post'] and obj['POST'] will return different values.
axios has method get, post etc, as lowercase, you are trying to access them via uppercase, therefore u getting an undefined value.
You can fix that by converting the method variable to lowercase.
import axios from 'axios';
export default function apiCall(method, path, data) {
return new Promise((resolve, reject) => {
return axios[method.toLowerCase()](path, data)
.then(res => {
return resolve(res.data);
})
.catch((err) => {
console.log(err)
reject(err)
});
});
}
BTW, axios methods are already returning Promises, so you can make your code a bit simpler by using it.
import axios from 'axios';
export default function apiCall(method, path, data) {
return axios[method.toLowerCase()](path, data)
.then(res => res.data)
.catch((err) => {
console.log(err);
return Promise.reject(err);
});
}

I had the same issue and felixmosh gave me the key
const { data } = await axios.PUT(
`/api/users/profile/update/`,
user,
config
)
I fixed it changing the method and it worked to me ;)
const { data } = await axios.put(
`/api/users/profile/update/`,
user,
config
)

Related

After calling two API call and update two state, only the first state was updated as expected after rendering, why is that?

In my react project,
I have two states, one is Projection, other is called StressProjections
I have a function that will invoke two Api call, once the api return come back. It will update both state
Below is my code.
//call Api 1
axios
.post<IProjectionResponse>(`/api1`, normalProjectionRequest)
.then(res => {
const result = res.data.result
props.setProjection(result)
})
.catch(error => {
console.log(error)
})
//call Api 2
axios
.post<IStressProjectionResponse>(
`api2`,
stressProjectionRequest
)
.then(res => {
const result = res.data.result
props.setStressProjections(result)
})
.catch(error => {
console.log(error)
})
However, I notice that my StressProjections is always set with "" , empty value. But I am sure the api 2 call is valid, and the return does have something in it. But after rendering, only state Projection have response data in it, but no data in state StressProjections
So my suspicion is that you update a piece of state and rerender the component before the other request is done, but it is hard to tell without seeing the rest of the code.
Try this and see if it solves your issue (post more code if not):
const promise1 = axios.post<IProjectionResponse>(`/api1`, normalProjectionRequest)
const promise2 = axios.post<IStressProjectionResponse>(`api2`,stressProjectionRequest)
Promise.all([promise1, promise2])
.then(values => {
props.setProjection(**VAL HERE**)
props.setStressProjections(**VAL HERE**)
})
.catch(err => {
console.log(err)
})
For the future, it is generally better practice to package multiple requests in a Promise all, this way you have to write way less code for error handling etc.
If you need to know which promise failed:
const promise1 = new Promise((resolve, reject) => {
axios
.get("https://api.github.com/users/niklasbec")
.then((data) => {
resolve(data);
})
.catch((err) => {
reject(err);
});
});
const promise2 = new Promise((resolve, reject) => {
axios
.get("https://api.github.com/users/noneexistinguser123")
.then((data) => {
resolve(data);
})
.catch((err) => {
reject(err);
});
});
Promise.allSettled([promise1, promise2]).then((vals) => {
console.log(vals);
vals.forEach((val, index) => {
if(val.status === "rejected") {
if(index === 0) {
//ERROR handling 1
console.log("error in promise 1")
} else {
//ERROR handling 2
console.log("error in promise 2")
}
}
})
});
This will let you do whatever you want with the error handling, hope that helps.
BTW: If you are wondering why I am wrapping the axios promise in another promise, I have to resolve manually so I can pass the response value of the request, maybe axios has a native way to do it but I don't know of one. Anyway, it works.

Using JS native fetch() api in React ComponentDidMount() results in a pending Promise

I was trying to load data into my project from the public folder in the componentDidMount() lifecycle method. However, I didn't get the desired FeatureCollection Object but a pending Promise.
componentDidMount = () => {
...
const data = fetch(`vcd/${this.state.monthFile}`)
.then(response => response.text())
.then(async data => {
return csv2geojson.csv2geojson(data, {
latfield: 'lat',
lonfield: 'lng',
delimiter: ','
}, (err, data) => {
if (err) console.log(err);
console.log(data); // correctly outputs a FeatureCollection, length 30277
return data;
// this.setState({ someAttribute: data }) => Also doesn't work.
})
})
.then(data => data); // If to use another Promise chaining, the result would be undefined.
console.log(data); // a pending Promise
}
My file contains 30277 rows * 3 columns, ~500Kb in size, which I think shouldn't be a problem with data loading, and after consulting the csv2geojson and fetch API, I still can't think of a solution to this problem. I am grateful for any helpful inputs.
EDIT: Using both async-await pattern and chaining another .then would result in undefined.
JS Fetch returns a promise so its because you're returning that promise.
So just change your code like this it will work;
import React, { useEffect, useState } from "react";
export default function ExampleHooks() {
const [data, setData] = useState(null);
var csv2geojson = require("csv2geojson");
useEffect(() => {
fetch("https://gw3xz.csb.app/sample.csv")
.then((response) => response.text())
.then(async (data) => {
csv2geojson.csv2geojson(
data,
{
latfield: "lat",
lonfield: "lng",
delimiter: ","
},
(err, data) => {
if (err) console.log(err);
setData(data);
}
);
});
}, []);
return <div onClick={() => console.log(data)}>show data</div>;
}
or as a Class Component:
import React from "react";
var csv2geojson = require("csv2geojson");
class ExampleClass extends React.Component {
state = {
data: null
};
componentDidMount() {
fetch(`vcd/${this.state.monthFile}`)
.then((response) => response.text())
.then(async (data) => {
csv2geojson.csv2geojson(
data,
{
latfield: "lat",
lonfield: "lng",
delimiter: ","
},
(err, data) => {
if (err) console.log(err);
this.setState({ data: data });
}
);
});
}
render() {
return <div onClick={() => console.log(this.state.data)}>show data</div>;
}
}
export default ExampleClass;
Working example over here
fetch returns a promise, and that is what you save to data. If you want to log the "data", then you have a couple options.
Log it IN the promise chain (you already do that)
Convert over to async/await and await the fetch to resolve/reject
code
componentDidMount = async () => {
...
const data = await fetch(`vcd/${this.state.monthFile}`)
.then(response => response.text())
.then(data => {
return csv2geojson.csv2geojson(data, {
latfield: 'lat',
lonfield: 'lng',
delimiter: ','
}, (err, data) => {
if (err) console.log(err);
console.log(data);
return data;
})
});
console.log(data); // a resolved/rejected Promise result
}

How to use async function and export it correctly with React Native?

My question is about correctly implementing an async function to fetch data. I've a function called _getData() and I'm calling it on the componentDidMount() of a screen. But when server response is slow, switching to this screen is getting slower. So I would like to use async function for fetching data. But I'm not sure if I'm doing it correctly. Is that a correct approach? I can't be sure if it works async or not.
Here is my Api._getData() code:
const _getData = async () => {
return await axios.get("http://blabla.com/someservice", { params: someParamDataHere });
};
export const Api = {
_getData
};
and on SomeScreen.js, I also have loadData() function which calls the function above and does state updates.
loadData() {
Api._getData()
.then((response) => {
this.setState({ myData: response.data });
})
.catch((error) => {
console.log(error.response);
});
}
in componentDidMount() function of the same screen I'm calling this loadData()  function directly.
Now, is it enough to declare Api._getData() as async and using await in it, or should I change some trigger functions too?
Thank you very much for your help.
instead of async await use promises
export const getRequest = (url) => {
return new Promise((resolve, reject) => {
api
.get(url)
.then((response) => {
handleReponse(response)
.then((errorFreeResponse) => {
resolve(errorFreeResponse);
})
.catch((error) => {
reject(error);
});
})
.catch((error) => {
reject(handleError(error));
});
});
};
You are doing correct while retrieving in load Data . What you can do more is try more syntactical sugar of es6 by using async await in loadData , hence
loadData = async() =>{
try{
let response = await Api._getData();
this.setState({ myData: response.data });
} catch(err){
console.log(error.response);
}
}
Hope it helps. feel free for doubts

Testing fetch using Jest- React Native

I have a common api class that i use for handling api calls in React Native. It will make the call and get the json/ error and return it. See the code below.
// General api to acces data from web
import ApiConstants from './ApiConstants';
export default function api(path,params,method, sssid){
let options;
options = Object.assign({headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}},{ method: method }, params ? { body: JSON.stringify(params) } : null );
return fetch(ApiConstants.BASE_URL+path, options).then( resp => {
let json = resp.json();
if (resp.ok) {
return json;
}
return json.then(err => {
throw err;
}).then( json => json );
});
}
But when i write the jest test to mock the api as folllows in tests folder.
test('Should login',() => {
global.fetch = jest.fn(() => new Promise((resolve) => {
resolve( { status: 201, json: () => (mock_data_login) });
}));
return Api(ApiConstants.LOGIN,{'un':'test1','pwd':'1234'},'post', null).then((data1)=>{
expect(data1).toBeDefined();
expect(data1.success).toEqual(true);
expect(data1.message).toEqual('Login Success');
});
});
it fails with:
TypeError: json.then is not a function
When I change the fetch return to this, the test passes:
return fetch(ApiConstants.BASE_URL+path, options).then( resp => {
let json = resp.json();
return json
});
}
Why is this type error error popping up? I can't change the API module, because that will my redux saga code to change. What should I do?
In your code, json is just an Object and not a Promise, so then is undefined. That's the complain you are getting because you are trying to use undefined as a function. The problem is not in the test but in your code that ha san error. Try the following instead.
return fetch(ApiConstants.BASE_URL+path, options)
.then(resp => resp.json())
.then( json => json)
.catch((error) => error);
});
Edit: oh, just read you can't make changes to the component where the error occurs?
Try converting your fetch like this:
return fetch(ApiConstants.BASE_URL+path, options)
.then(resp => {
let json = resp.json();
if (resp.ok) {
return json;
} else {
throw Error(resp.error) // assuming you have some kind of error from endpoint?
}
})
.then(/*handle your ok response*/)
.catch(/*handle your error response*/);
I faced the same issue, The problem is that you are mocking only response.json as function but it should be a Promise, Like this,
global.fetch = jest.fn(() => new Promise((resolve) => {
resolve( { status: 201, json: () => {
return Promise.resolve(mock_data_login);
}
});
}));
This will return a Promise for you json function.
Hope this fix your problem.

Dispatching an action from a service in Redux

I have a logging function which logs errors. When an Ajax Request fails with a non JSON data type, the log method should log it, however, we are getting the mutated error as the attached screenshot shows. I am trying to call this log action within a service.
Code
...
import {log} from '../actions/LoggingActions';
...
export default function request(url, opts, dispatch, type = 'application/x-www-form-urlencoded') {
...
return new Promise((resolve, reject) => {
$.ajax(args).then((data) => {
dispatch(httpEndRequest([url, opts, dispatch]));
resolve(data);
}).fail((jqXHR, textStatus, errorThrown) => {
const error = (jqXHR && jqXHR.responseJSON) ?
jqXHR.responseJSON.message :
'Error Making Request';
dispatch(httpFailRequest([url, opts, dispatch], error));
try {
reject(JSON.parse(jqXHR.responseText));
} catch (e) {
console.log(jqXHR.responseText, jqXHR, error);
reject(error);
dispatch(log('Received data is not in JSON format', {requestUrl: url}, {result: e, response: jqXHR, status: textStatus, error: errorThrown}, 'error'));
}
});
});
}
Instead of using jQuery with React, Use axios or fetch (Promise based HTTP clients). I personally prefer axios.
To use axios, do
npm install axios --save. Then
import axios from 'axios';
return new Promise((resolve, reject) => {
axios.get(url, {
params: params
})
.then((response) => {
resolve(response.data);
})
.catch((error) => {
// error.response.status
dispatch(log(error));
reject(error);
});
});

Resources