React: how can I process the data I get from an API before I render it out? - reactjs

I have no issues fetching the data from an API using useEffect. That works fine.
The problem is that I need to apply some processing to the data before I actually render it out (in this case, I need to shuffle the array that I receive).
I tried a million different ways, but I just can't find the right place to write that logic. Basically, it won't work anywhere.
What is the right way of going about this?

you can do everything with data before setState.
is useEffect when you fetched data from Api, shuffle it and then do setState.
little example:
useEffect(() => {
axios.get("http://example.com/data").then(response => {
const data = shuffle(response.data);
setState(data);
})
});

useEffect(() => {
const fetchData = async () => {
await axios.get("http://example.com/data").then(response => {
const data = shuffle(response.data);
setState(data);
});
};
fetchData();
return () => {
// Clean up func
}
}, []); //[] will prevent infinite API calling.

Related

How do i put a setstate function that is already within an async function, within a useEffect hook?

I am working on a project, which is a django project with REACT as the frontend. For the homepage, there is a useState variable ('room_code') that is used. The setstate variable is set_room_code. So, i have an async function that fetches the room code from an api and then the idea is to use the set_room_code hook. But this is just not working. The issue is with the set_room_code as the code works if i simply remove it. I have tried to search up ideas but i am short on it. Any input would be appreciated.
useEffect( () => {
let fetch_code = async () => {
const response = await fetch('/api/user-room');
const data = await response.json();
console.log('hi');
console.log(data.room_code);
console.log('bhao');
set_room_code(data.room_code);
};
fetch_code();
console.log(hi);
}, []);
I have tried using an extra useEffect hook but that doesnt work as well
A few things, first its best practice to name the useState variable
const [roomCode, setRoomCode] = useState();
FYI.
Now as to your question--
useEffect( () => {
let fetch_code = () => {
fetch('/api/user-room').then((data) => {
setRoomCode(data.room_code);
console.log(data.room_code);
return response.json();
});
};
fetch_code();
console.log("this should show your RoomCode", roomCode)
}, [roomCode]);

ReactJS array from usestate is still empty after setTimeout

please I'm solving one problem (just learning purposes). I'm using useState() hook and then, after some timeout I want add next items into array from remote fetch.
My code snippet look like:
const [tasks, setTasks] = useState([]);
const url = 'https://pokeapi.co/api/v2/pokemon?offset=0&limit=5';
// asnynchronous call. Yes, it's possible to use axios as well
const fetchData = async () => {
try {
let tasksArray = [];
await fetch(url)
.then((response) => response.json())
.then((data) => {
data.results.map((task, index) => {
// first letter uppercase
const taskName = task.name.charAt(0).toUpperCase() + task.name.slice(1);
tasksArray.push({ id: index, name: taskName });
});
});
console.log('Added tasks:' + tasks.length);
setTasks(_.isEmpty(tasks) ? tasksArray : [...tasks, tasksArray]);
} catch (error) {
console.log('error', error);
}
};
useEffect(() => {
// Add additional example tasks from api after 5 seconds with
// fetch fetchData promise
setTimeout(fetchData, 5000);
}, []);
Code works fine with useEffect() hook. But in async function my array is empty when I add some tasks within five seconds and it will be replaced by fetched data and one empty
I added Butter and Milk within 5 seconds to my Shopping list
But after timeout my tasks array will be replaced by remote fetched data.
And as you can see, tasks array lenght is 0 (like console.log() says)
Please, can you exmplain me, why my tasks array is empty if there exists 2 items before 5 seconds.
Of course, I'm adding my tasks to the list normally after hit Enter and handleSubmit
const handleSubmit = (e) => {
e.preventDefault();
//creating new task
setTasks([
{
id: [...tasks].length === 0 ? 0 : Math.max(...tasks.map((task) => task.id)) + 1,
name: newTask,
isFinished: false,
},
...tasks,
]);
setNewTask('');
}
Thanks for help or explain. It the problem that useEffect is called after rendering? Of this causing async behavior?
I could not understand your code fully correctly but my guess is
the fetchData function you have declared might refer to the tasks at the time of declaration.
so every time you call fetchData you might not see the changed tasks state...
if this is the case try using useCallback with the dependency tasks...
what useCallback does is it stores the function in memory and if smth in dependency changes the function's logic changes to dependencies you declared.
If you have used eslint, calling a function inside useEffect will give you error similar to below
The ‘fetchOrg’ function makes the dependencies of useEffect Hook (at line 6) change on every render. Move it inside the useEffect callback. Alternatively, wrap the ‘fetchOrg’ definition into its own useCallback() Hook
Your code is confusing. You can place everything inside an useEffect, and I believe the thing you are trying to achieve is a long poll query. (for that you use setInterval() and you have to clear the function in useEffect
my solution for you:
const [tasks, setTasks] = useState([]);
const url = 'https://pokeapi.co/api/v2/pokemon?offset=0&limit=5';
const request = {method: GET, Headers: {"Content-type":"application/json"}}
useEffect(() => {
function fetchData(){
fetch(url, request).then(res => res.json().then(data => {
data.results.map((task, index) => {
const taskName = task.name.charAt(0).toUpperCase() + task.name.slice(1);
setTasks((prevState) => ([...prevState,{ id: index, name: taskName }]));
});
})
}
const interval = setInterval(() => {
fetchData();
}, 5000)
return () => clearInterval(interval)
}, []);
please do not forget two things:
This approach is only good when you have 5 to 10 simultaneous clients connected since it is not performance effective on the backend, I would recommend instead an alternative based on realtime communication (with the listening for new events.
please do not forget to specify the {method, headers, body) in the fetch function

Results from realtime db not available when called

Im having some trouble with realtime database and react native.
I have the following useEffect in a component that is supposed to listen for changes and then update state as required, I then use that state to populate a list.
The component gets a data object passed as a prop, the data object contains a string array called members that contains uuids, I am trying to iterate over those to get the attached user from realtime db and then save those objects to a state array.
const myComponent = ({ data }) => {
const [users, setUsers] = useState([]);
useEffect(() => {
const userArr = [];
data.map(item => {
item.members.forEach((username: string) => {
database()
.ref(`users/${username}`)
.on('value', snapshot => {
userArr.push(snapshot.val());
});
});
});
setUsers(userArr);
};
}, []);
return (
<>
{users} <----- this is in a flatlist
</>
);
}
It works eventually after refreshing the screen about 5 times. Any help would be greatly appreciated.
The simplest way to get some data to show is to move update the state right after you add an item to the array:
useEffect(() => {
const userArr = [];
data.map(item => {
item.members.forEach((username: string) => {
database()
.ref(`users/${username}`)
.on('value', snapshot => {
userArr.push(snapshot.val());
setUsers(userArr); // 👈
});
});
});
};
}, []);
Now the UI will update each time that a user is loaded from the database.
I also recommend reading some more about asynchronous loading, such as in Why Does Firebase Lose Reference outside the once() Function?
Your database call may be asynchronous, which is causing the code inside the useEffect to act a little funny. You could push all those database calls (while iterating through item.members) into an array, and then do Promise.all over the array. Once the promises are resolved, you can then set the users.
Hope this helps!
add an async function inside useEffect and call it
useEffect(() => {
const getUsers = async () => {
const userArr = [];
data.....
//wait for it with a promise
Promise.all(userArr).then(array => setUsers(array))
})
getUsers()
}, [])
not sure if the function needs to be async

What's the best practice of calling API data from a function outside useEffect?

While working with react useEffect hook, most of the example I came across in case of calling api data in useEffect hook for initiate the component is, calling api directly inside useEffce hook.
For instance,
useEffect(() => {
async function(){
const res = await axios.get(`https://jsonplaceholder.typicode.com/${query}`);
setData(res.data)
}
}, []);
But what about fetch data outside the hook with a method ? For instance,
const getData = () => {
async function(){
const res = await axios.get(`https://jsonplaceholder.typicode.com/${query}`);
setData(res.data)
}
useEffect(() => {
getData(); // here eslint shows an warning "Promise returned from setData is ignored"
}, [])
is there any specific reason for avoiding second example. If not what's the proper way to call api call function in useEffect hook with proper cleanup ?
In React component file
useEffect(() => {
loadData(query).then(setData)
}, [query])
crate another service file to serve data from API
in service file
export const loadData = async query => {
const res = axios.get(`https://jsonplaceholder.typicode.com/${query}`);
return res.data;
// You can put this API call in try catch to handle API errors
};
Creating a separate function for calling an api is a perfect example of loading data in useEffect. You can give it parameters if you would have a paginated endpoint and call it multiple times or add polling to the page to load the data by interval. I can only see benefits by creating a function for this.
useEffect(() => { fetch("./product.JSON") .then(res => res.json()) .then(data => setProducts(data)) }, [])

How correctly fetch and save data inside an array using useEffect

I am using React and asynchronously fetching data from the blockchain with useEffect.
What I do not understand is that while the console.log inside the map function works and it prints the right data, supposedly it should save that data inside data array, but when I log data outside the map (meaning it should have finished to save the data) I get an array of undefined values.
Code:
useEffect(() => {
const data = mainnet.Vaults.map((pool) => {
const loadLendingData = async () => {
const dataPool = await getPoolInfo(pool);
console.log('dataPool', dataPool) //all good it prints everything
return dataPool
};
loadLendingData();
})
console.log('data', data) //[undefined, undefined, undefined and so on]
setData(data)
}, []);
Why is this happening? What am I doing wrong?
EDIT:
I fixed the problem by storing data with useState for each loop in map.
Code:
useEffect(() => {
mainnet.Vaults.map((pool) => {
const loadLendingData = async () => {
const dataPool = await getPoolInfo(pool);
setLendingData((prevPool) => [...prevPool, dataPool])
};
loadLendingData();
})
}, []);
But still I'd like to understand why the first example didn't work.
I see that you are not returning anything from the map function, that's why the array has undefined elements outside the map function.
return loadLendingData()
This should solve the problem for you.

Resources