how to get all data from a request - reactjs

I receive data from the server and try to get "name" from the "one" object and get an undefined error. If you remove the replacement in request, the line "fetchData (response.data)" with "fetchData (response.data.one)" and in the selector "return state.one.name;" to "return state.name;" the result returns data. What is causing this error? Query and reference to the same objects.
request
export function fetchData (data) {
return {
type: "GET_DATA_REQUEST",
payload: data
}
}
export function fetchDataRequest(url) {
return(dispatch)=> {
fetch(url)
.then(response => {
if (!response.ok) {
throw new Error(response.statusText);
}
return response;
}
)
.then(response => response.json())
.then(response => dispatch(fetchData(response.data)))
}
}
selector
export const getRequestCity = (state) => {
return state.one.name;
}

You can check if the object one is present before accessing it like below -
export const getRequestCity = (state) => {
if (state.one) {
return state.one.name;
}
}

Related

Re-Usable fetch function with query string

I have a fetch function inside of my react component, which I wish to "outsourse" in a separate component.
export const fetchBooksBySubject = (selectedValue) => {
const options = {
method: `GET`,
};
fetch(`${server}/books?subjects_like=${selectedValue}`, options)
.then((response) => {
if(response.ok){
return response.json()
}
throw new Error('Api is not available')
})
.catch(error => {
console.error('Error fetching data: ', error)
})
}
Basically selectedValue is a prop coming from a child of App.jsx. As soon as the value is selected in a component, fetch should fire with this value in a query string. I tried to export the function above as a component and use it in App.jsx
useEffect(() => {
fetchBooksBySubject(selectedValue).then(data => setBookList(data));
}, [selectedValue])
const handleChange = e => {
setSelectedValue(e);
fetchBooksBySubject(selectedValue);
};
But this throws Property 'then' does not exist on type 'void'.
Here's a custom hook you can use with fast and reusable data fetching, a built-in cache, and other features like polling intervals and revalidation.
Hook:
const useBooks = (selectedValue) =>
{
const fetcher = (...args) => fetch(...args).then(res => res.json())
const { data, error } = useSWR(`/api/books?subjects_like=${selectedValue}`, fetcher)
return {
books: data,
isLoading: !error && !data,
isError: error
}
}
Usage:
const { books, isLoading, isError } = useBooks(selectedValue)
if (isLoading) return <div>Loading...</div>
else return <div>Your content here</div>
swr docs
Without swr:
useEffect(() =>
{
const fetchData = async (selectedValue) =>
{
const books = await fetchBookBySubject(selectedValue)
setBookList(books)
}
fetchData(selectedValue)
}, [selectedValue, bookList])
So the problem was, that I wasn't returning my fetch. I am a beginner, so my understanding is, that my App.js just couldn't access the data from fetchBooksBySubject withot this return
const dev = process.env.NODE_ENV !== 'production';
const server = dev ? 'http://localhost:3001' : 'https://your_deployment.server.com';
// later definable for developement, test, production
export const FetchBooksBySubject = (selectedValue) => {
const options = {
method: `GET`,
};
return fetch(`${server}/books?subjects_like=${selectedValue}`, options)
.then((response) => {
if(response.ok){
return response.json()
}
throw new Error('Api is not available')
})
.catch(error => {
console.error('Error fetching data: ', error)
})
}
Same as here:
let sum = (a,b) => {a+b}
sum(1,2) //undefined
let sum1 = (a,b) => {return a+b}
sum1(1,2) //3

Return the fetch response from another file

I am trying to call a function that calls fetch to an API from a React component in a separate file and am not finding the correct solution to get the correct response back.
When I debug, the result returns before the updateAccount function has completed and the final result is never returned to my update function.
Inside the fetch, the API returns the correct response whether it is successful or has validation errors and those results are correctly assigned to result.success and result.errors but the result doesn't get returned from the function so that the caller can make use of those values.
Inside of my React component:
import { updateAccount } from '../services/requests';
...
const update = (account: EditAccountModel) => {
const result = updateAccount(account);
if(result.errors.length > 0) {
// will notify of errors
console.log(result.errors); // is an empty array instead of validation errors
} else {
// will notify of success
console.log(result.success); // is an empty string instead of success message
}
}
...
My request file
export const updateAccount = (account: EditAccountModel | undefined): EditAccountResponseModel => {
const result = new EditAccountResponseModel();
fetch(baseUrl, {
method: 'PUT',
body: JSON.stringify(account),
headers
})
.then(response => {
if (!response.ok) {
return Promise.reject(response);
}
result.success = `${account?.name} was updated successfully!`
})
.catch(error => {
if (typeof error.json === "function") {
error.json().then(jsonError => {
result.errors.push(jsonError);
}).catch(genericError => {
result.errors.push(genericError);
});
}
});
return result;
}
The result reassignment happens inside then catch but it won’t be affective in the way you expected. The guaranteed way to return correct result is via a callback() passed to your updateAccount() if you could afford it:
export const updateAccount = (
account: EditAccountModel | undefined,
callback: Function
): EditAccountResponseModel => {
const result = new EditAccountResponseModel();
fetch(baseUrl, {
method: 'PUT',
body: JSON.stringify(account),
headers
})
.then(response => {
if (!response.ok) {
return Promise.reject(response);
}
result.success = `${account?.name} was updated successfully!`
callback(result);
})
.catch(error => {
if (typeof error.json === "function") {
error.json().then(jsonError => {
result.errors.push(jsonError);
callback(result);
}).catch(genericError => {
result.errors.push(genericError);
callback(result);
});
}
});
}
And inside your React component:
const update = (account: EditAccountModel) => {
const handleResult = (res) => {
// your result callback code
// ...
};
updateAccount(account, handleResult);
// ...
}
Alternative way that keeps your current structure is to change your current updateAccount() to an async function, then return await fetch().
You need to wait for the response . I'll let read more about how Promise work in JavaScript.
I wouldn't code updateAccount the same way you did, especially where you use the variable result and update it inside the flow of the promise (you really don't need that). You're also using React so you can use the state to store and update the result of the update function. But let's fix your problem first:
export const updateAccount = async (account: EditAccountModel | undefined): EditAccountResponseModel => {
const result = new EditAccountResponseModel();
await fetch(baseUrl, {
method: 'PUT',
body: JSON.stringify(account),
headers
})
.then(response => {
if (!response.ok) {
return Promise.reject(response);
}
result.success = `${account?.name} was updated successfully!`
})
.catch(error => {
if (typeof error.json === "function") {
error.json().then(jsonError => {
result.errors.push(jsonError);
}).catch(genericError => {
result.errors.push(genericError);
});
}
});
return result;
}
First make your function updateAccount async then await the result of the promise.
Now the same thing for the function update:
const update = async (account: EditAccountModel) => {
const result = await updateAccount(account);
if(result.errors.length > 0) {
// will notify of errors
} else {
// will notify of success
}
}

How to fetch data from MongoDB?

I am trying to use Express + MongoDB building React app.
I was able to post some documents to MongoDB. Currently, I'm trying to figure out how to print fetched data to the screen.
I have these routes:
router.post('/totalbalance', (request, response) => {
const totalBalance = new TotalBalanceModelTemplate({
totalBalance:request.body.totalBalance,
});
totalBalance.save()
.then(data => {
response.json(data);
})
.catch(error => {
response.json(error);
});
});
router.get('/totalbalance', (request, response) => {
TotalBalanceModelTemplate.find(request.body.totalBalance, (error, data) => {
if (error) {
return error
} else {
response.json(data[0])
}
})
});
This is axios request:
useEffect(() => {
const resp = axios.get('http://localhost:4000/app/totalbalance');
console.log(resp);
}, []);
It returns a promise that has a parameter data which equals to object value which is the first value in the array
data: {_
id: "60c48b4ec60919553d92319f",
totalBalance: 5555,
__v: 0
}
and prints it out to the console.
How can I print out to the console the value totalBalance instead of whole promise?
By the way, sometime the array of data is empty (there are no documents in the DB), how should i handle these cases as well?
Thanks!
First of all, Axios GET method does not have any request body. But you are trying to use it in the MongoDB query. - "TotalBalanceModelTemplate.find(request.body.totalBalance, (error, data) => {".
The find query should be object {}. If require pass on conditions to it.
First point, to print only "totalBalance" output. Use, console.log(resp.totalBalance);
Second point, to handle records length, have a if else condition,
if (error) {
return error
} else if (data.length) {
return response.send("No records found")
} else {
response.json(data[0])
}
Try this :
Routes
router.post("/totalbalance", async (req, res) => {
try {
const totalBalance = new TotalBalanceModelTemplate({
totalBalance: req.body.totalBalance,
})
await totalBalance.save();
res.json(totalBalance)
} catch (error) {
res.status(400).json({
message: error.message
})
}
})
router.get("/totalbalance", async (req, res) => {
try {
const totalBalances = await TotalBalanceModelTemplate.find();
res.json(totalBalances)
} catch (error) {
res.status(400).json({
message: error.message
})
}
})
App.js
import React, { useState, useEffect } from 'react';
import axios from 'axios';
export default function App() {
const [data, setData] = useState([]);
const getData = async () => {
try {
const response = await axios.get('http://localhost:4000/app/totalbalance');
await setData(response);
} catch (error) {
console.log(error);
}
};
useEffect(() => {
getData();
}, []);
return (
<div>
{data <= 0 ? (
<div className="empty">
<p>No data!</p>
</div>
) : (
data.map((d) => (
<ul key={d.id}>
<li>{d.totalBalance}</li>
</ul>
))
)}
</div>
);
}

React Redux Axios Api Get call with path parameters

I am trying to do a axios get call to my backend server with path variable and save the response data to the store. Unfortunately it only works for the get call with no path variables. still I can also log the response in the console, but I am unable to dispatch the response.data to the store
fetchByCardNumber: (CardNumber) => axios.get(baseURL+'loyalty/loyaltyCustomer/card/'+ CardNumber)
export const fetchByCardNumber = (CardNumber) => dispatch => {
LoyaltyAPI().fetchByCardNumber(CardNumber)
.then(response => {
if (response.status !== 200){
dispatch(Customer(null))
} else {
dispatch(Customer(response.data))
}
}).catch(error => {
return error;
})
}
But wherever I have used the url without pathVaribale in axios get call it works.
Eg : fetchCards: () => axios.get(baseURL+'loyalty/loyaltyCard/all')
While using the above URL I can dispatch the response to the store and get it.
//use it like that without curly braces between {cardNumber}
fetchByCardNumber: (CardNumber) => axios.get(baseURL+'loyalty/loyaltyCustomer/card/'+ CardNumber)
export const fetchByCardNumber = (CardNumber) => dispatch => {
LoyaltyAPI().fetchByCardNumber(CardNumber)
.then(response => {
if (response.status !== 200){
dispatch(Customer(null))
} else {
dispatch(Customer(response.data))
}
}).catch(error => {
return error;
})
}
The issue was with the way on dispatching the response to the store. The below code worked.
export const fetchByCardNumber = (CardNumber) => dispatch => {
LoyaltyAPI().fetchByCardNumber(CardNumber)
.then(response => {
if (response.status !== 200){
store.dispatch(SelectedCustomer(null))
} else {
store.dispatch(SelectedCustomer(response.data))
}
}).catch(error => {
return error;
})
}

Can't return response from redux-thunk

I'm calling an action from a component:
this.props.createWebsite(this.state)
This calls an action and passes in some state. The action looks like this:
export const createWebsite = data => {
return (dispatch, getState) => {
return axios.post(
API.path + 'website/',
{
// some data
}
)
.then(response => {
})
.catch(error => {
})
}
}
I want to handle the response and error in the component that called this, rather than in the action itself. How can I do this? I have tried:
this.props.createWebsite(this.state).then(response => { /**/ }).catch(error => { /**/ })
This sort of works but it doesn't catch errors.
You need to remove the catch from the createWebsite declaration.
It handle the error and to not propagate it. So the error is lost.
To get it :
remove the catch
export const createWebsite = data => {
return (dispatch, getState) => {
return axios.post(
API.path + 'website/',
{
// some data
}
)
.then(response => {
return response;
})
}
}
rethrow the exception
export const createWebsite = data => {
return (dispatch, getState) => {
return axios.post(
API.path + 'website/',
{
// some data
}
)
.then(response => {
return response;
})
.catch(error => {
// Do something
throw error;
})
}
}

Resources