axios does not work with while fetch does - node.js

i want to get data (array) from /{url} and i tried this code
// Fetch the list on first mount
componentDidMount() {
this.getList();
}
// Retrieves the list of items from the Express app
getList = () => {
fetch('/main')
.then(res => res.json())
.then(list => this.setState({ list }))
}
this is working fine but then i decided to switch to axios and tried literally same code
// Fetch the list on first mount
componentDidMount() {
this.getList();
}
// Retrieves the list of items from the Express app
getList = () => {
axios.get('/main')
.then(res=> res.json())
.then(list => this.setState({list}))
}
but it did not worked and gave me error in this line: .then(res=> res.json())
so i do not know what is problem if anyone knows the clue i will be glad if you tell me

// Fetch the list on first mount
componentDidMount() {
this.getList();
}
// Retrieves the list of items from the Express app
getList = () => {
axios.get('/main')
.then(res=> res.data)
.then(list => this.setState({list}))
.catch(error => this.setState({error: error.message}))
}

It is because axios has different response, instead of res.json() return data already like : return res.data or pass it to state directly something like
getList = () => {
axios.get('/main')
.then(res=> this.setState({list: res.data}))

i would recommend some changes in your design, as im using axios successfully in many projects, its not a requirement but it helps and is working very reliable:
Create a service like api.js
import axios from 'axios';
export default axios.create({
baseURL: `http://my.api.url/`
});
Then you can use it like this
import API from '../Services/api'; // this is your service you created before
LoadStats = async event => {
try {
var response = await API.get('api/targetroute');
if (response.data != null) {
this.setState({
stats: {
mydata: response.data
}
});
console.log('Receiving result: '+JSON.stringify(response.data));
}
} catch (error) {
console.log('ERROR: '+error)
}
}

Related

How to send React to Express server get Request passing id

Hello I am learning on MERN Stack dev, so I am trying to implement a get request where by I send in and ID and then try searching through the collection by the id the return the entry back to the client so I have been trying to implement this but I do not know where I am going wrong because I get a 404 response
Code below is the client side where I try to send through the get request
const ProductDetails = (props) => {
const product_id = window.location.href.split("/")[4];
console.log(product_id);
const getProduct = () => {
const url = `http://127.0.0.1:5000/single-women-clothes/id?=${product_id}`;
Axios.get(url)
.then((response) => {
console.log(response.data);
})
.catch((error) => {
console.log(error);
});
};
getProduct();
return (
<div>
<h1>Details</h1>
</div>
);
};
router.get("/single-womens-clothes/:id", (request, response) => {
console.log(request.params);
MongoClient.connect(
mongoURI,
{ useNewUrlParser: true, useUnifiedTopology: true },
(error, client) => {
client
.db("OnlineStore")
.collection("WomensClothes")
.find(request.params.id)
.toArray()
.then((data) => {
response.status(200).json(data);
})
.then((response) => {
console.log("Single Female Product Fetch Successful");
})
.catch((error) => {
console.log(error);
});
}
);
});
Can I please get help on how I can pass the ID to the server then search through collection through this given ID
Anytime you have a 404 error, the issue is usually coming from putting the wrong url.
In your front-end:
single-women-clothes/id?=${product_id}
Backend
/single-womens-clothes/:id
You are missing an "s" in the front-end url in "womens"
To answer your second question:
You shouldn't do id?= just simply leave it as
single-women-clothes/${product_id}

How do i dispatch a redux action from class and not component

import axios from "axios";
class ApiCaller {
CallApi = (SERVICE_URL, data) => {
return new Promise((resolve, reject) => {
axios.post(SERVICE_URL, data).then(function (response) {
var data = response.data
if (data.status) {
data = data.data
resolve(data)
} else {
if (data.isExpired != undefined && data.isExpired) {
console.log('here in expired')
}
reject(data.message)
}
}).catch(function (error) {
console.log(error);
reject(error)
});
})
}
}
export default new ApiCaller();
// export default connect()(new ApiCaller());
here i am calling all the webservices throughout application
and data.isExpired is a boolean where server tells me that provided jwt token is expired and i need to remove user information from redux and navigate to login again i have used this method almost more than 50 places and i cant afford it to change on all those places
how can i dispatch user logout from here ?
import { logoutUser } from "app/redux/actions/UserActions";
const mapStateToProps = state => ({
logoutUser: PropTypes.func.isRequired
});
export default withRouter(connect(mapStateToProps, { logoutUser })(ApiCaller));
this might be the solution , to do that i need to extend component and it will break ApiCaller implementation on other places
i have tried functional components too but it isnt helping, i need to logout from my ApiCaller so i don't need to handle jwt expire exception on every single view
i am new to React Redux
anyone please
I think this is a pretty good example of where you can use Redux Thunks.
// this is an action that can be dispatched to call the api
function callApi() {
return (dispatch) => {
apiCaller.CallApi()
.then(() => {
dispatch(callApiSuccess()); // success action defined elsewhere
})
.catch(() => {
dispatch(callApiError()); // error action defined elsewhere
});
}
}

why do we need thunk.withExtraArgument?

I currently have an issue with my code so while I am debugging i am trying to understand which approach shall I take in order to solve the issue.
I am using google oauth with passport.js. from client I have an action to fetch the authentication.
import axios from "axios";
const axiosInstance = axios.create({
baseURL: "http://localhost:3000/api",
timeout: 3000,
});
export const fetchUser = () => async (dispatch, getState, api) => {
try {
await axiosInstance.get("/auth/current_user").then((res) => {
dispatch({ type: FETCH_USER, payload: res.data });
});
} catch (e) {
console.log(e.message);
}
};
here is the client-side store set up:
const store = createStore(
reducers,
window.INITIAL_STATE, //
applyMiddleware(thunk)
);
and this is the server side store set up:
export default (req) => {
const store = createStore(reducers, {}, applyMiddleware(thunk));
console.log("store from servre", store);
return store;
};
Another approach would be instead of defining axiosInstance in action, i define it when I create the client side store and pass it to thunk.withExtraArgument iike this.
const axiosInstance = axios.create({
baseURL: "/",
});
const store = createStore(
reducers,
window.INITIAL_STATE,
applyMiddleware(thunk.withExtraArgument(axiosInstance))
);
I changed the action accordingly:
export const fetchUser = () => async (dispatch, getState, api) => {
try {
await api.get("/auth/current_user").then((res) => {
dispatch({ type: FETCH_USER, payload: res.data });
});
} catch (e) {
console.log(e.message);
}
};
My question which method should I use. CUrrently I have issue in both methods :) . But if i know which way is correct then I will solely focus on that method.
Thank You
I will suggest you go with with creating an instance of axios in a file and importing it whereever you need it, instead of adding it as an argument to thunk
api.js
import axios from "axios";
const axiosInstance = axios.create({
baseURL: "http://localhost:3000/api",
timeout: 3000,
});
export default axiosInstance;
actions.js
import api from '/path/to/api';
export const fetchUser = () => async (dispatch, getState) => {
try {
await api.get("/auth/current_user").then((res) => {
dispatch({ type: FETCH_USER, payload: res.data });
});
} catch (e) {
console.log(e.message);
}
};
The advantage of the above solution is that you can import and use the instance for making direct API calls too in your components for which you do not need to dispatch actions to the reducers.

POST request with Axios not sending data to my server

Here is my React code for the form submission:
const handleSubmit = (e) => {
e.preventDefault();
console.log('item:', item);
Axios.post('http://<MY_SERVER>/item/add', {name:item})
.then(response => console.log(response))
.catch(err => console.log(err));
};
and this is the code in my Node API:
// Add a new Item
app.post('/item/add', (req, res) => {
const newItem = new Item({
name: req.body.name
});
newItem.save()
.then(item => {
res.json({msg: 'success'});
})
.catch(err => console.log(err));
});
When I run the handleSubmit nothing happens. I only get the console.logs... Also, here is the error from my server
'ValidationError: item validation failed: name: Path' `name` is required
So it is clear that the data sent over to the api is never received. I've tried changing it up in many ways I have came across online but no luck.
I have attached both ways to post data i.e. Form URL Encoded and JSON. For sending Form Url Encoded data we need an additional Library querystring.
You can install it using npm install query-string
Here is the code for both the requests. You don't need query-string if you are using content type application/json.
Here you go
var axios = require('axios');
const qs = require('querystring');
function sendFormUrlEncodedData() {
const headers = {
'Content-Type': 'application/x-www-form-urlencoded'
};
const payload = {
name: 'morpheus',
job: 'leader'
};
//Send data with form url using querystring node package for it.
axios
.post('https://reqres.in/api/users', qs.stringify(payload), {
headers: headers
})
.then(res => {
console.log(res.data);
})
.catch(err => {
console.log(err);
});
}
function sendJSONData() {
const headers = {
'Content-Type': 'application/json'
};
const payload = {
name: 'morpheus',
job: 'leader'
};
//Send data with JSON, so stringifying it.
axios
.post('https://reqres.in/api/users', JSON.stringify(payload), {
headers: headers
})
.then(res => {
console.log(res.data);
})
.catch(err => {
console.log(err);
});
}
sendFormUrlEncodedData();
sendJSONData();
First of all check whether your backend code is working or not by using postman. I think you are getting validation error because of the error of your backend code. And also check whether that you are implemented the name attribute correctly with its data type.
After that update, the react code as below.
import axios from 'axios';
constructor() {
this.item = {
name: ''
}
}
handleSubmit(event) {
console.log('item:', this.item.name);
event.preventDefault();
axios.post('http://<MY_SERVER>/item/add', this.item)
.then(response => {
console.log(response.data);
})
.catch(error => {
console.log(error);
});
}

React: Data won't be saved to this.state

So I am trying to send a get request to my node server which is responding by sending a list of objects that I wish to display on my page.
Tried many different methods, but I cant seem to find a solution. Also I am rendering via the server if that's any help.
Client Code:
class BookTools extends React.Component {
constructor(props) {
super(props);
this.state = {
books: []
};
this.handleAdd = this.handleAdd.bind(this);
this.handleEdit = this.handleEdit.bind(this);
this.handleDelete = this.handleDelete.bind(this);
this.updateList = this.updateList.bind(this);
fetch('/getbooks').then(function (res) {
return res.json();
}).then(function (json) {
console.log(json);
const data = JSON.stringify(json);
console.log(data);
this.setState({ books: data})
});
}
Can't use componentDidMount since it's SSR and can't seem to get componentWillMount to work either, so i tried doing it in the constructor as suggested by another. both console.logs prints out the correct response.
I have also tried doing both this.setState({ books: json.body }) and this.setState({ books: json.data }) with no other result. And yes i am quite new to react as well as node/express
Thanks for any help :)
It’s common issue in react. When you use regular function this context won’t be available so either you need to bind it or change it to arrow function.
Also make sure the API returns data
Change
fetch('/getbooks').then(function (res) {
return res.json();
}).then(function (json) {
console.log(json);
const data = JSON.stringify(json);
console.log(data);
this.setState({ books: data})
});
To
fetch('/getbooks')
.then(res => res.json())
.then(json => {
console.log(json);
const data = JSON.stringify(json);
console.log(data);
this.setState({ books: data})
});
Or
fetch('/getbooks')
.then(function (res) {
return res.json();
}.bind(this))
.then(function (json) {
console.log(json);
const data = JSON.stringify(json);
console.log(data);
this.setState({ books: data})
}.bind(this));

Resources