Why is the initial state getting printed along with the data? - reactjs

I am fetching data from a backend api.
const Home = () => {
const [posts,setPosts]=useState([]);
useEffect(()=>{
const fetchPosts= async ()=>{
const res = await axios.get("/posts")
setPosts(res.data);
}
fetchPosts();
},[])
console.log(posts)
However in doing this, the initial state of posts which is [] is also getting printed.
Why is this happening and how can I avoid this and only get the data?

that is the reason why you see loading in real-world App because communication between server and client takes time so we show loading or show error if API gets error the same logic goes to component or element whatever your are trying to show as well
if(posts.length > 0) {
console.log(posts)
} else {
console.log("Loading...")
}

Related

How to fetch data from api when new data is added to it using UseEffect React

I'm trying to build a chat app, the issue that i'm facing is the following:
When i open the chat the useEffect render the function to fetch all the message inside that particular chat and return it to me, but if i add a new message on that particular chat the hooks is not updated and do not show the new message
Here is the code
const ChatWindow = () => {
const [loadMessage, setLoadMessage] = useState([])
const [message, setMessage] = useState({
message: ""
})
useEffect(() => {
loadMessageInChat()
},[]);
//Api call to load message
const loadMessageInChat = async() => {
try {
const attempt = await axios.get(`https://bbobras.onrender.com/api/messages/${openWindow.chatInfo._id}`,config)
if(attempt.status === 200){
//This will return an [{}]
setLoadMessage(attempt.data.data)
}
} catch (error) {
console.log(error)
}
}
}
export default ChatWindow;
I know that passing an empty array on useEffect will only call loadMessageInChat() once, so i thought to pass the hook loadMessage into it, but doing that will create an infinite loop and fetch the data over and over again because what i get from the api is an [{}] so if i'm not wrong i understand this behaviour as {} === {} --> False and that's why the infinite loop.
Sorry but i'm so junior in react and i'm trying to solve this but i can't get any solution.
Thanks!

Firebase Storage async request with "listAll" method. React

I'm getting an image from a user and storing it with in Cloud Storage through Firebase. The storing works fine.
Right after that I'm requesting all images from the storage to display them, but I got the response without the last submit. So I need to refresh the page, then useEffect make one more request and everything works.
UPD. Here's the the complete logic:
This function is uploading image to the storage:
const uploadImage = async (image,imageName) => {
if (image == null) return;
const imageRef = ref(storage,`images/${imageName}`);
try {
uploadBytes(imageRef, image);
} catch (err) {
alert(`${err}`)
}
}
This function does request to firestore, but doesn't return last uploaded image every time, just randomly. sometimes it does, usually not :
const getImages = async () => {
try {
const imagesListData = await listAll(imagesListRef);
setImagesList([]);
imagesListData.items.forEach(item => {
getDownloadURL(item).then(url => setImagesList(prev => [...prev,url]));
})
} catch(err){
alert(err.message);
}
}
after refreshing the page, useEffect does the job :
useEffect(() => {
getImages();
},[])
As I said above sometimes it works as I expected from the first try without me changing the code(which is the most confusing),most of the times I need to refresh the page to get the last image.
p.s. list() instead listAll() give same results

response is shown in network but returns empty array when logged in console (React)

I'm fetching data from api to render it on a component. The network tab on inspect shows the response object.
My code of the component here:
`
const NormalDetails = (props) => {
const [allCustomers, setAllCustomers] = useState([]);
useEffect(() => {
const getAllCustomers = () => {
try {
const response = salesService.getAllCustomers();
if (response.status == 200) {
setAllCustomers(response.data.object);
}
} catch (error) {
console.log("error fetching data");
}
};
getAllCustomers();
console.log(allCustomers);
}, []);
`
But while logging the response in console, it returns an empty array:
According to the React official docs, state updates may be asynchronous, meaning you may not see the updated state instantly.
You are logging allCustomers just after you update the state with setAllCustomers to response.data.object. You might be actually logging the initial state ([]) to the console instead of the updated one. try logging the response data itself instead of the state to assure correct response, or add some checking mechanism to useEffect to log the state only if its not [].

RTK query send data, is coming back manipulated

At work, I need to make an infinite scroll pagination with RTK-query. I am using Firestore as a DB, and I made a very basic version with just async functions super quickly. Now I need to convert what I have made to RTK query.
As I was doing this I noticed I was not longer able to fetch more data from Firestore because my query with Firestore was not responding. After doing some digging, I found out that RTK query is somehow changing my data. I will explain below with my code. This very well would be a Firestore problem as well.
async queryFn() {
try {
const { prod, lastDoc } = await fetchInitialData();
return { data: { prod, lastDoc } };
} catch (err) {
return { error: err };
}
This is how I am sending my data with RTK-query, I left a lot of code out since it is not needed. Down below is my react file, that calls my RTK query hook, as well as checks to see if the data being sent from RTK is correct
const [products, setProducts] = useState<BasicProductData[] | null>();
const [lastDocSaved, setLastDocSaved] = useState<any>();
const { data, isLoading, isError, error, isSuccess, refetch } = useFetchProductsQuery(null);
useEffect(() => {
getPost();
if (data && lastDocSaved) {
console.log(data.lastDoc === lastDocSaved);
}
}, []);
const getPost = async () => {
const { prod, lastDoc } = await fetchInitialData();
setProducts(prod);
setLastDocSaved(lastDoc);
};
As you can tell both of these ways of getting the initial data is pretty much exactly the same. Finally here is my pagination function, to fetch more data from firebase to keep the infinite scroll going.
const getMorePosts = async () => {
const postData = await fetchMoreData(lastDocSaved);
setLastDocSaved(postData.lastDoc);
setProducts([...products, ...postData.prod]);
};
I know that 'data' I get back from the RTK hook is not the same since I manually have checked if is by using that console.log in the useEffect. I also know it does not work since if I setLastDocSaved(data.lastDoc) the pagination does not work.
This is strange to me, since both data.lastDoc and const { lastDoc } = await fetchInitialData() come back as pretty much identical in the console, however lastDoc properly queries from firebase and data.lastDoc does not.

Why is useEffect not working here? Do I need to change the condition?

I am trying to run this code, but useEffect is not running a single time.
export default function DetailPage() {
const [post, setPost] = useState({});
const postId = useParams().postId;
console.log(postId);
useEffect(() => {
console.log("useEffect called");
const fetchPost = async () => {
const res = await axios.get(`/posts/${postId}`);
setPost(res.data);
console.log(post);
console.log("useEffect runs");
};
fetchPost();
console.log("useEffect runs 2 ");
}, [postId]);
}
Here, I am getting postId in the console, but not "useEffect run".
I have used similar code (except I am using another variable there instead of postId) in another file, and it's working there.
Please help me with this code.
Be careful, when you use setState the value of your state is changed asynchronously. So to you, it seems that the state doesn't change, but in reality, it will change.
This because when you try to print the value of a state just after the setState, its value still wasn't updated.
When you want to debug how a state changes with console log, create a separate hook that log every change.
Add something like this:
useEffect(()=>{
console.log("Post state changed!")
console.log(post);
},[post])
For what concerns the issue that your last log (console.log("useEffect runs");) is not running the only possible issues are:
postId changes are not triggering useEffect (possible reason: you are using a ref inside your useParams to store values). To check it just put a console.log before running the Axios request:
const fetchPost = async () => {
//Does this ever display your postId? If it does go to point 2.
console.log(`Trying to fetch post ${postId}`);
//Furthermore if postId can be undefined I'll wrap this request with an if
const res = await axios.get(`/posts/${postId}`);
setPost(res.data);
console.log("useEffect runs");
};
There is an uncaught error in your network request.
First tip: always put a try-catch block when awaiting an Axios response.
This will avoid missing uncaught errors.
try {
const res = await axios.get(`/posts/${postId}`);
setPost(res.data);
} catch(e) {
//Here log your error. Remember to avoid showing the log in production
}
When working with Axios I also always suggest checking the network tab of your browser to understand what is going on with your request.
I link you a post where I explain how to do it: https://stackoverflow.com/a/66232992/14106548

Resources