React Native Doesn`t re-render after context state change - react-native

state changes after getting data from api. i can see that with console.log()
but doesn`t render data after update. there is my code fetch code :
useEffect(() => {
axios
.get(
'https://mylink.ngrok.io/channels/getUser',
).then((data)=>{
let array = [];
const promises = data.data.channels.map((channel)=>{
axios.get(`https://mylink.ngrok.io/channels/getChannel/${channel}`).then((resp)=>{
array.push(resp.data);
})
})
Promise.all(promises).then(()=>{
setonLineChannels(array);
});
})
}, []);
btw its in context.
I think Promise.all casue of that
thx

Where you declare promises, it's not going to wait for those API requests to complete. They're running even before you've called Promise.all(promises).
You can just put the code you've defined as promises inside the Promise.all() directly, then make sure you return the get request inside. And don't push to array. Your map will return an array of promises, and you can use the results array in the .then after Promise.all to update your state directly.
Here's what I mean:
useEffect(() => {
axios.get("https://mylink.ngrok.io/channels/getUser").then((data) => {
Promise.all(
data.data.channels.map(
(channel) =>
axios
.get(`https://mylink.ngrok.io/channels/getChannel/${channel}`)
.catch((err) => console.error(err)) // this allows an individual request to fail
)
).then((results) => setonLineChannels(results));
});
}, []);

Related

How to restrict call multiple api call in useEffect in react-native?

I am new in React-Native, I am facing one issue in my app and not able to resolved that yet. All thing is working but first time API being calling two time unnecessary.
Here is my useEffect method :-
useEffect(() => {
if (transactions.length === 0) {
setIsAPICall(true);
}
getTransactions().then((response: any) => {
dispatch(actionTransitionsBadge(0));
setTransactions(response);
setIsAPICall(false);
});
}, [user, onChainBalance]);
In this method I have to get transaction list when component first time open. After that I have to refresh this list when user and onChainBalance get updated. The thing is working but when I am loading this component first time then the api is calling multiple time.
What I can do to manage this flow that once component load then api call once after then when my two state changed the api call again.
Put your getTransactions in the useCallback, like this:
const fetchData=useCallback(
() => {
getTransactions().then((response: any) => {
dispatch(actionTransitionsBadge(0));
setTransactions(response);
setIsAPICall(false);
});
},
[],
)
Then call fetchData in the useEffect
Here is some Details where you can useEffect .
useEffect(() => {},)
useEffect(() => {},[])
useEffect(() => {},[dependency_array])
Here I am explaining them one by one
The first would call on every render
The Second would call two time
the third would call two times and when the dependency array changes
Here is your use Case
useEffect(() => {
if(user !== null && user !== undefined && transactions.length === 0){
getTransactions().then((response: any) => {
dispatch(actionTransitionsBadge(0));
setTransactions(response);
setIsAPICall(false);
});
}
}, [user, onChainBalance]);
but Still this is not a good method. you should use react-query or redux-toolkit-query

Nuxt await async + vuex

Im using nuxt and vuex. In vuex im getting data:
actions: {
get_posts(ctx) {
axios.get("http://vengdef.com/wp-json/wp/v2/posts").then(post => {
let posts = post.data;
if (!posts.length) return;
let medias_list = "";
posts.forEach(md => {
medias_list += md.featured_media + ","
});
medias_list = medias_list.slice(0, -1);
let author_list = "";
posts.forEach(md => {
author_list += md.author + ","
});
author_list = author_list.slice(0, -1);
axios.all([
axios.get("http://vengdef.com/wp-json/wp/v2/media?include=" + medias_list),
axios.get("http://vengdef.com/wp-json/wp/v2/users?include=" + author_list),
axios.get("http://vengdef.com/wp-json/wp/v2/categories"),
]).then(axios.spread((medias, authors, categories) => {
ctx.commit("set_postlist", {medias, authors, categories} );
})).catch((err) => {
console.log(err)
});
})
}
},
In vuex state i have dynamic postlist from exaple below.
How i can use it in Nuxt?
In nuxt i know async fetch and asyncData.
async fetch () {
this.$store.dispatch("posts/get_posts");
}
Thats not working.
How i can say to nuxt, wait loading page, before vuex actions loading all data?
As you already mentioned there are:
fetch hook
asyncData
And differences are well described here
The reason why your code is not working might be in your store action.
It should return a promise, try to add return before axios get method ->
get_posts(ctx) {
return axios.get(...
// ...
And then, on your page:
async fetch () {
await this.$store.dispatch("posts/get_posts");
}
Also, in comment above you're saying that you dont want to commit data in store:
...load page only after vuex, i dont need to pass data in vuex
But you do it with this line:
ctx.commit("set_postlist", {medias, authors, categories} );
if you dont want to keep data in store, just replace line above with:
return Promise.resolve({ medias, authors, categories })
and get it on your page:
async fetch () {
this.posts = await this.$store.dispatch("posts/get_posts");
// now you can use posts in template
}
Misread the actual question, hence the update
With Nuxt, you can either use asyncData(), the syntax will change a bit tho and the render will be totally blocked until all the calls are done.
Or use a combo of fetch() and some skeletons to make a smooth transition (aka not blocking the render), or a loader with the $fetchState.pending helper.
More info can be found here: https://nuxtjs.org/docs/2.x/features/data-fetching#the-fetch-hook
Older (irrelevant) answer
If you want to pass a param to your Vuex action, you can call it like this
async fetch () {
await this.$store.dispatch('posts/get_posts', variableHere)
}
In Vuex, access it like
get_posts(ctx, variableHere) {
That you can then use down below.
PS: try to use async/await everywhere.
PS2: also, you can destructure the context directly with something like this
get_posts({ commit }, variableHere) {
...
commit('set_postlist', {medias, authors, categories})
}

Using a state variable in Axios put request in React Native

I am modifying a state variable (setTokens(tokens - 1)) in React native and then using the modified variable in an axios PUT request (library_tokens: tokens).
The problem is, the put request is successful, but it puts the old value of the variable instead of the modified one in the database after the PUT request.
The following is the code:
const [tokens,setTokens] = useState(0)
const lendBook = book => {
// Add book to the IssueReturn collection in the database
issuesApi
.post('/bookissue', {
booksIssued: book._id,
image: book.image,
user: context.stateUser.user.userId,
})
.then(response => {
if (response.status === 200) {
// Decrement user's library token
setTokens(tokens - 1);
// Modify the user's library tokens
userProfileApi
.put(
`/${context.stateUser.user.userId}`,
{
library_tokens: tokens,
},
{
headers: {Authorization: `Bearer ${jwtToken}`},
},
)
.then(response => {
console.log('tokens', tokens);
});
}
})
.catch(err => {
console.log(err);
});
};
You can use useEffect like this.
useEffect(() => {
console.log(tokens) // do something after state has updated
}, [tokens])
After state updation the useEffect will be called, so you can call userProfileApi inside useEffect.
setTokens it not a synchron function. code executed afterwards will not have the updated state. either use a local variable to store the result of token - 1 or make use of the useEffect hook.

useState in React Native get data of previous state

I have one state
const [data, setData] = useState("");
And 2 useEffects that call in parallel when component renders
useEffect(() => {
socket.on("message",()=>{
console.log(data)
})
}, [socket])
useEffect(() => {
const res = getDataFromServer()
setData(res.data)
}, [isLoading])
2nd useEffect get data from server and set state but when socket arrive in first useEffect data is on initial state that is empty. How can I get updated state data in first useEffect when socket arrives. If I set data as dependency to first useEffect then socket event is reinitialized and callback is calling multiple times.
You can return a function in useEffect to clean unnecessary handlers / event listeners.
Effects with Cleanup - React Docs
In this function you can use the offAny method of socket.io client to remove previous listener.
useEffect(() => {
const currentListener = socket.on("message",()=>{
console.log(data)
});
return () => {
socket.offAny(currentListener);
};
}, [socket, data]);
This might help
React.useEffect(() => {
// This effect only executes on the initial render so that we aren't setting up the socket repeatedly.
socket.on("message",()=>{
console.log(data);
})
return () => {
socket.off('message',() => {});
}
}, []);

Getting updated redux state after dispatch with react hooks

I'm using the action expensesActions.getExpenseList to get a list from the database, which in turns updates the store in expense.expenseList
I'm calling the action inside useEffect hook and would like to get back the list from the store once it's retreived.
My code below is not working because the order is incorrect, if I refresh (with save) I do have the list. How can I change the code so my list is retreived once the actions is complete?
const fetchedList = useSelector(state => state.expense.expenseList);
// Get expense list
useEffect(() => {
const loadList = async () => {
setIsLoading(true)
await dispatch(expensesActions.getExpenseList())
calculateAverageExpense()
}
loadList()
}, [dispatch]);
You can have a second useEffect like this:
useEffect(() => {
if (fetchedList.length) calculateAverageExpense();
}, [fetchedList])
This will execute calculateAverageExpense every time your list change.