How to update state object in useEffect - reactjs

How to update state object in useEffect
Hi All,
In my React app I am calling an online service in order to get some WIFI information. Eventually, I would like to show\render the information of the wifiData to the user.
const [macAddress, setMacAddress] = useState('');
const [wifiData, setwifiData] = useState({});
const axios = require("axios");
const ClientOAuth2 = require('client-oauth2')
const clientAuth = new ClientOAuth2({
accessTokenUri: 'https:....',
clientId: '....',
clientSecret: '....',
scopes: ['....']
})
const wifiService = useCallback(() => {
clientAuth.credentials.getToken().then(function (user) {
if (user.accessToken) {
axios({
method: "post",
url: "....access_token=" + user.accessToken,
data: {
....,
},
}).then(function (response) {
// setwifiData ??
console.log(response.data)
}).catch(function (error) {
console.log(error);
});
}
})
}, [axios, clientAuth.credentials, macAddress])
useEffect(() => {
if (!openDrawer && macAddress !== "") {
wifiService();
// setwifiData ??
}
}, [wifiService, clientAuth.credentials, openDrawer, macAddress]);
return (
<div style={{ padding: 20 }}>
// render wifiData
)
How can I store the response data in wifiData ?
What is the proper way to deal with this type of scenario? I couldn’t figure it out.
Appreciate the help
Thank you

Set the state inside wifiService():
const wifiService = useCallback(() => {
clientAuth.credentials.getToken().then(function (user) {
if (user.accessToken) {
axios({
method: "post",
url: "....access_token=" + user.accessToken,
data: {
....,
},
}).then(function (response) {
// ** put response in correct format here if you need to
setwifiData(response)
console.log(response.data)
}).catch(function (error) {
console.log(error);
});
}
})
}, [axios, clientAuth.credentials, macAddress])
Remove wifiService from useEffect triggers to prevent infinite loop:
useEffect(() => {
if (!openDrawer && macAddress !== "") {
wifiService();
}
}, [clientAuth.credentials, openDrawer, macAddress]);

Related

How to add a common parameter to All API's Redux-toolkit-Query

i am using Redux-Toolkit-Query in Reactjs Project, I have Number of end points. For Each Endpoint i have to add one common parameter with body , i tried below snippet on QueryStarted adding that Language parameter, but i am repeating this code for each enpoint and sometimes its not working.
updatePassword: builder.mutation({
query: (body) => ({
url: URL.UPDATE_PASSWORD,
method: "POST",
body: body,
responseHandler: (response) => response.json(),
validateStatus: (response, result) =>
response.status === 200 && result.success === 1,
}),
transformResponse: (response) => {
return response;
},
async onQueryStarted(body, { dispatch, queryFulfilled, getState }) {
const language = await UTILS?.asyncLocalStorage.getLanguage(); //Here How to add this with body
body.language = language;
const { history } = body;
try {
dispatch(LoaderAction.setLoading(true));
const { data } = await queryFulfilled;
if (data) {
UTILS.handleSuccesNotification(
data?.message ?? "Password updated sucessfully"
);
history.goBack();
}
} catch (err) {}
dispatch(LoaderAction.setLoading(false));
},
}),

React - how to wait for API response to return component?

I am new to react and I am building a page component that returns data from an API call and passes the values to my return statement. My page continues to return as blank because the page loads before the variables are returned from the API. I am wondering, how can I wait to render the page until my API has returned a response? The two variables are initialized as so and are not updated until the API response
var userData
const [customer_email, setEmail] = useState();
const [newuserid, setUserId] = useState();
useEffect(() => {
userData = Cookies.get("user-data");
if (userData) {
console.log("Userdata !== null");
try {
userData = JSON.parse(userData);
} catch (e) {
console.log(e);
}
setEmail(userData.email);
setUserId(userData.userID);
}
}, []);
function getCustomer() {
const options = {
method: "GET",
headers: {
Accept: "application/json",
"x-guid": "......",
"x-api-key": ".....",
},
};
if (customer_email != "" && customer_email != undefined) {
try {
console.log("email inside fetch =", customer_email);
fetch(
`https://exampleapi/customers?customer_email=${customer_email}&customer_id=${newuserid}`,
options
)
.then((response) => response.json())
.then((response) => console.log(response))
.catch((err) => console.log(err));
} catch (e) {
console.log(e);
}
}
}
if (customer_email) {
console.log("get customer");
getCustomer();
}
The component return statement:
return (
<>
{customer_email && (
<section>
<div
id="identification"
data-authenticated="true"
data-email={customer_email}
data-id={newuserid}
style={{ display: "none" }}
></div>
</section>
<div>
........{irrelevant html here}
</div>
)}
);
Note---- This is not a class, it is a function component
You might want to do something like this where you have a loading state that you set to true when the response from the API has been resolved, which will re-render the component.
Note: This code will not work if you copy and paste. It's just a representation of the pattern you should use.
var userData
const [customer_email, setEmail] = useState();
const [newuserid, setUserId] = useState();
cost [hasLoaded, setHasLoaded] = useState(false);
function getCustomer() {
const options = {
method: "GET",
headers: {
Accept: "application/json",
"x-guid": "......",
"x-api-key": ".....",
},
};
if (customer_email != "" && customer_email != undefined) {
try {
console.log("email inside fetch =", customer_email);
fetch(
`https://exampleapi/customers?customer_email=${customer_email}&customer_id=${newuserid}`,
options
)
.then((response) => response.json())
.then((response) => console.log(response))
.catch((err) => console.log(err));
} catch (e) {
console.log(e);
}
}
}
useEffect(() => {
userData = Cookies.get("user-data");
if (userData) {
console.log("Userdata !== null");
try {
userData = JSON.parse(userData);
} catch (e) {
console.log(e);
}
setEmail(userData.email);
setUserId(userData.userID);
}
}, []);
useEffect(async () => {
if (!customer_email) return;
console.log("getting customer")
const customerData await getCustomer()
if (customerData) setHasLoaded(true)
}, [])
return(
<>
{hasLoaded && <div>.....</div>}
</>
)

useEffect: How to put data in the state in order

I'd like to ask how to retrieve data through use Effect.
The flow I want is as follows.
First, I want to get the 'cards' state, fill the cards with data, and then fill the data through the cardsPromises after that.
But my code couldn't get cards and wordAll, and the empty value came out.
I think it's because the cards are still empty, but I don't know how to operate in order.
Please tell me how to do it.
const [wordAll, setWordAll] = useState([]);
const [cards, setCards] = useState([]);
useEffect(() => {
axios
.get("http/api/words/", {
headers: {
Authorization: cookies.token,
},
})
.then((response) => {
setCards(response.data);
})
.catch((error) => {
console.log(error);
});
const cardsPromises = cards.map((contents) =>
axios.get(
`http/api/words/detail_list/?contents=${contents.contents}`,
{
headers: {
Authorization: cookies.token,
},
}
)
);
console.log("cards", cards);
Promise.all(cardsPromises)
.then((response) => {
console.log("resp", response.data);
setWordAll(response.data);
})
.catch((error) => {
console.log("err==>", error);
});
}, []);
You are correct, cards array is still empty in the useEffect callback when the fetching the data. I suggest converting to async/await and waiting for the first fetch to resolve and using that value of cards for the fetching of the rest of the data.
const [wordAll, setWordAll] = useState([]);
const [cards, setCards] = useState([]);
useEffect(() => {
const fetchData = async () => {
try {
const{ data: cards } = await axios.get(
"http/api/words/",
{
headers: {
Authorization: cookies.token,
},
},
);
setCards(cards);
const cardsPromises = cards.map((contents) =>
axios.get(
`http/api/words/detail_list/?contents=${contents.contents}`,
{
headers: {
Authorization: cookies.token,
},
}
);
);
const wordAllResponse = await Promise.all(cardsPromises);
const wordAll = wordAllResponse.map(({ data }) => data);
setWordAll(wordAll);
} catch (error) {
// handle any errors, rejected Promises, etc..
}
};
fetchData();
}, []);
Wrap your 2nd axios call inside a function, and call it after 1st axios call returns.
useEffect(() => {
const getWords = (cards) => {
const cardsPromises = cards.map((contents) =>
axios.get(
`http/api/words/detail_list/?contents=${contents.contents}`,
{
headers: {Authorization: cookies.token}
}
)
);
Promise.all(cardsPromises)
.then((response) => {
setWordAll(response.data);
})
.catch((error) => {
console.log("err==>", error);
});
})
axios
.get("http/api/words/", {
headers: { Authorization: cookies.token },
})
.then((response) => {
const cards = response.data;
setCards(cards);
getWords(cards);
})
.catch((error) => {
console.log(error);
});
}, [])
Now dependency chain is clearer.

How to set fetch data to text field in react-native function component

I am learning react-native and have a question about fetching data and passing them to a text component.
I fetched my data from my node.js back-end but don't know how to pass this data to component. Below is the code that i have tried so far.
const TableView = () => {
const [details, setDetails] = useState('');
const getUserData = async () => {
fetch('https://----.herokuapp.com/getIncomePerUser', {
method: 'post',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
email: data,
month: value,
}),
})
.then(response => response.json())
.then(response => {
console.log('Test');
console.log(response);
const array = response;
for (const i of array) {
const total = i.total;
setDetails(total);
console.log(total);
}
})
.catch(err => {
console.log(err);
});
});
};
useEffect(() => {
getUserData();
}, []);
return (
<Text Value={details}></Text> //I need to set my fetch data this text component
)
}
if you have an array of values and you want to show them you can use:
const TableView = () => {
const [details, setDetails] = useState('');
const getUserData = async () => {
fetch('https://----.herokuapp.com/getIncomePerUser', {
method: 'post',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
email: data,
month: value,
}),
})
.then(response => response.json())
.then(response => {
setDetails(response.map(r => r.total));
})
.catch(err => {
console.log(err);
});
});
};
useEffect(() => {
getUserData();
}, []);
return (<>
{details.map((d, i) => <Text key={i}>{d}</Text>)}
</>)
}
if you have a single value just replace your text component with:
<Text>{details}</Text>

Expo Download file. FileSystem Download Async method POST with body

I need a way to make a request with method Post passing a body but I didnt find a way to do it. The documentation: https://docs.expo.io/versions/latest/sdk/filesystem/ only show the GET method, I need a way to make a post request passing the body.
FileSystem.downloadAsync(${baseUrl}/v1/paycheck/pdf, FileSystem.documentDirectory + ‘file.pdf’,
{
headers: {
‘Authorization’: localToken
},
httpMethod: ‘POST’,
body: {
type: 'monthy',
year: '2021',
month: 2,
employer: {
name: "Pink",
}
}
}
)
.then(({uri}) => {
Sharing.shareAsync(uri, {dialogTitle: 'Salvar ou Compartilhar'})
})
.catch(error => {
console.error(error);
});
}
As far as I understand your problem
My Approach for Downloading and Sharing the PDF would be
Writing these two functions
// Execute this function when you to share the file...
const GetPDF = async () => {
try {
const response = await fetch(`${baseUrl}/v1/paycheck/pdf`, {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
Authorization: "localToken",
},
body: JSON.stringify({
type: "monthy",
year: "2021",
month: 2,
employer: {
name: "Pink",
},
}),
});
const content = await response.json();
DownloadThenShare(content); // Some URI
} catch (error) {
console.error(error);
}
};
Now DownloadAndShare function
// This function will execute after Download has been completed successfully
const DownloadThenShare = async (uri) => {
const downloadInstance = FileSystem.createDownloadResumable(
uri,
FileSystem.documentDirectory + "file.pdf"
);
const result = await FileSystem.downloadInstance.downloadAsync();
if (result.status === 200) {
Sharing.shareAsync(result.uri, { dialogTitle: "Salvar ou Compartilhar" });
} else {
console.log("Failed to Download");
}
};
I finally managed to make it work using axios e FileReader();
const response = await axios.post(`${baseUrl}/v1/paycheck/pdf`, data, {responseType: 'blob'});
const fr = new FileReader();
fr.onload = async () => {
const fileUri = `${FileSystem.documentDirectory}/document.pdf`;
const result = await FileSystem.writeAsStringAsync(fileUri, fr.result.split(',')[1], {encoding: FileSystem.EncodingType.Base64});
saveFile(fileUri);
};
fr.readAsDataURL(response.data);

Resources