React state data not showing on first component render - reactjs

Here is my code I'm looking to get followers data from Firestore and then fetching users from doc id but I'm getting data in the console log but data not showing on the first time component render but when I click the tab for the second time it renders data and correct followers users showing can someone tell me what I am doing wrong ?
export default function RequestTab() {
const [followers, setfollowers] = useState(null)
useEffect(() => {
if (firebase.auth().currentUser) {
let data = [];
db.collection("buddiez")
.where("followeeId", "==", firebase.auth().currentUser.uid)
.where("accepted", "==", false)
.onSnapshot((querySnapshot) => {
querySnapshot.forEach((doc) => {
db.collection("users").doc(doc.data().followerId).get().then((result) => {
data.push({ ...result.data() })
});
});
});
setfollowers(data)
}
}, [])
console.log(followers);
let userArr = followers ? followers.map((follower, i) => {
return <div key={i} className="request-details pb-3 border-bottom">
<div className="noty-usepf-icon">
<img className="rounded-circle mt-0" style={{ width: "45px", height: "45px" }} src={follower.profilePic ? follower.profilePic : ""} alt="" />
</div>
<div className="request-info">
<h3 className="mb-n1" style={{ fontSize: '1.1rem' }}>{follower.fullName}</h3>
<span>#{follower.username}</span>
</div>
<div className="accept-feat">
<ul>
<li><button type="submit" className="accept-req">Accept</button></li>
<li><button type="submit" className="close-req"><i className="la la-close" /></button></li>
</ul>
</div>
</div>
}) : <h2 className="text-muted p-3 d-flex justify-content-center">No Requests !</h2>
return (
<div className="tab-pane show active">
<div className="acc-setting">
<h3>Requests</h3>
<div className="requests-list">
{userArr}
</div>
</div>
</div>
)
}

I assume Following code db.collection("users").doc(doc.data().followerId).get() is async, so setfollowers(data) will happen before these promises are resolved, so data will be empty, you have to wait until all promises are resolved and then set state, you can use Promise.All for this case.

Related

how to fix Can't perform a React state update on an unmounted component ERROR

I have this component in React that is using Algolia searchClient.
const Hit = ({hit}) => {
const [socialNetworkHtml, setSocialNetworkHtml] = useState([]);
useEffect(() => {
let socialNetwork = hit['Social Network'];
let socialNetworkHtml = socialNetwork.map((network, index) => {
return (
<span key={index}>
<img className='small-logo' src={require(`../../assets/socialNetworks/${network}.png`)}/>
</span>
);
});
setSocialNetworkHtml(socialNetworkHtml);
return () => {
setSocialNetworkHtml([]);
};
}, [hit]);
return (
<div className="hit-card">
<a target="_blank" rel="noreferrer" href={`${hit.Website}`}>
<div style={{ backgroundImage: `url(${hit.Image})` }} className="card-image"></div>
<h4 className="hit-name">
<Highlight attribute="Name" hit={hit} />
</h4>
<b>Used for :</b>
{socialNetworkHtml}
<b>Works on:</b><br/>
<p className='hit-card--details'> {hit.Deployment}</p>
</a>
</div>
);
}
I am getting these error:
"uncaught TypeError: socialNetwork.map is not a function
at FindWhatYouNeed.js:34:1"
"Warning: Can't perform a React state update on an unmounted
component. This is a no-op, but it indicates a memory leak in your
application. To fix, cancel all subscriptions and asynchronous tasks
in a useEffect cleanup function."
When I try to switch the pages. Do you have any idea how i can fix it?
I am trying to convert a value from the object that is on the Algolia server, to an img.
I see three potential problems here:
your return callback in the useEffect.
return () => {
setSocialNetworkHtml([]);
};
it's trying to perform a state update, "setSocialNetworkHtml", when the component is unmounted. You can just remove it and not replace it with anything
Also, you shouldn't be creating the html in the useEffect, more something like:
const Hit = ({ hit }) => {
const [socialNetwork, setSocialNetwork] = useState([])
useEffect(() => {
setSocialNetworkHtml(hit['Social Network'])
}, [hit])
return (
<div className="hit-card">
<a target="_blank" rel="noreferrer" href={`${hit.Website}`}>
<div style={{ backgroundImage: `url(${hit.Image})` }} className="card-image"></div>
<h4 className="hit-name">
<Highlight attribute="Name" hit={hit} />
</h4>
<b>Used for :</b>
{socialNetwork.map((network, index) => (
<span key={index}>
<img
className="small-logo"
src={require(`../../assets/socialNetworks/${network}.png`)}
/>
</span>
))}
<b>Works on:</b>
<br />
<p className="hit-card--details"> {hit.Deployment}</p>
</a>
</div>
)
}
Thirdly, i'm not sure you should be using inline requires for the image sources, but i'm also not sure you shouldn't

Adding items to cart in react js

In reactjs, what code would I have to write in my two components(homepage.js with an add-to-cart button and a checkout page with a clear cart button? This is my Homepage.js where I fetch the items from my backend server, map, and display them on the page.
function Home() {
const [data, setData] = useState([]);
useEffect(() => {
// auto-login
fetch("/coffees").then((res) => {
if (res.ok) {
res.json().then((data) => setData(data))
}
});
}, [])
console.log(data)
return (
<>
<div className="box">
<div className="projo">
<h2 >Welcome to Coffee-cafe</h2>
</div>
<div className="projects">
{data.map((data) =>{
return(
<div className="card">
<img className="avatar" src={data.coffee_image} alt="coffee"></img>
<div className="card-content">
<h4><b>{data.coffee_name}</b></h4>
<p id="desc">{data.description}</p>
<p className="price">{data.price}</p>
{/* <p>{data.category}</p> */}
<button onClick={() => ({})} className="btn1" id="btn1">Add to Cart</button>
</div>
</div>
)
})}
</div>
</div>
</>
)
}
export default Home;
For the Checkout.js, this is what I have currently.
function Checkout() {
return (
<>
<div className="section">
<div className="photo">
<img className="dp" src={image1} alt="coffee"></img>
<div className="info">
<h3>Coffee:</h3>
<p>Price:</p>
<p>Category:</p>
<div className="check-out-btn">
{/* <button className="add">AddToCart</button> */}
<button className="delete">ClearCart</button>
</div>
</div>
</div>
</div>
take a look for a global states like redux , context,or zustand
for my recommendation, I suggest zustand is less code than context and redux and short learning curve
carts =[]
setItemToCart(item){
const isExist = carts.find(c => c.id ===item.id)
if(isExit){
const qty = isExit.qty+item.qty
const newItem= {...item,qty}
// push is not recommended to use because it mutates state
carts.push(newItem)
}else{
carts.push(item)
}
}

React Owl Carousel 2.3.3 - I loose dynamic data after refreshing page. Working fine on local data

I am using json-server and fetching data using fetch. First time I get data properly in an Owl Carousel and the slider works fine but after when I refresh the page all my dynamic data wipe out. Still my carousel slides but with no data. Also I have attached a jquery script https://code.jquery.com/jquery-3.2.1.slim.min.js in index.html.
I am loosing my Owl Carousel Dynamic Data which I am using through map method in the Owl Carousel Component. Below is the code where I am using my slider. Please help me to find where I am doing wrong. Thank You.
---------------
<<<<<- Below code is MainSlider.js ->>>>>
import React, { useReducer, useEffect } from "react";
import OwlCarousel from "react-owl-carousel";
import "owl.carousel/dist/assets/owl.carousel.css";
import { mainSliderReducer } from "../reducers/mainSliderReducer";
const API = "http://localhost:8000/mainSlider";
const initialState = {};
const MainSlider = () => {
const [state, dispatch] = useReducer(mainSliderReducer, initialState);
const { data } = state;
useEffect(() => {
getData();
}, []);
const getData = () => {
fetch(API)
.then((res) => {
if (res.ok) {
return res.json();
} else {
console.log("DATA NOT FOUND. SOME ERROR");
throw new Error("ERROR FETCHING DATA");
}
})
.then((data) => dispatch({ type: "GET_MAINSLIDER_DATA", payload: data }))
.catch((err) => console.log(err));
};
console.log(data);
return (
<>
<OwlCarousel className="owl-theme" loop margin={10} nav>
{data ? (
data.map((item) => {
const { id, heading, description, img, smallHeading } = item;
return (
<section key={id} className="dvMainSlider">
<div className="item bg bgcolor1 pb-md-5 pt-md-4 py-xl-0 h-100vh h-sm-auto h-xl-100vh">
<div className="container">
<div className="row slideInfo h-xl-100vh align-items-xl-center">
<div className="col-md-6 text-center">
<img
src={img}
className="img-fluid d-inline-block"
alt=""
/>
</div>
<div className="col-md-6 pt-lg-5 pt-xl-0 description">
<h1 className="text-white">{heading}</h1>
<h4 className="text-white">{smallHeading}</h4>
<p className="text-white">{description}</p>
<a href="--" className="btn btnPrimary mb-3 mt-sm-3">
Shop More
</a>
</div>
</div>
</div>
</div>
</section>
);
})
) : (
<h1>"SLIDE NOT FOUND"</h1>
)}
</OwlCarousel>
</>
);
};
export default MainSlider;
<<<<<- Below code is mainSliderReducer.js ->>>>>
export const mainSliderReducer = (state, action) => {
console.log(state, action);
switch (action.type) {
case "GET_MAINSLIDER_DATA":
return { ...state, data: action.payload };
default:
return state;
}
};
Hey I found my own question's answer and i found the way which i am sharing to you all. Just check if data is available then only you load the Owl Carousel Component. Check the code below for better understanding.
{data && (
<OwlCarousel {...options}>
{data.map((item) => {
const { id, heading, description, img, smallHeading } = item;
return (
<section key={id} className="dvMainSlider">
<div className="item bg bgcolor1 pb-md-5 pt-md-4 py-xl-0 h-100vh h-sm-auto h-xl-100vh">
<div className="container">
<div className="row slideInfo h-xl-100vh align-items-xl-center">
<div className="col-md-6 text-center">
<img
src={img}
className="img-fluid d-inline-block"
alt=""
/>
</div>
<div className="col-md-6 pt-lg-5 pt-xl-0 description">
<h1 className="text-white">{heading}</h1>
<h4 className="text-white">{smallHeading}</h4>
<p className="text-white">{description}</p>
<a href="--" className="btn btnPrimary mb-3 mt-sm-3">
Shop More
</a>
</div>
</div>
</div>
</div>
</section>
);
})}
</OwlCarousel>
)}

How to display data from firebase single document using React?

Before this, I'm using Snapshot and try to map it. But it failed for a single document. After I read back the documentations from firebase. They recommend using this way for a single document. But I don't know how to make it readable on the site rather than console. I want to send data on the title and essay.
const { id } = useParams()
useEffect(() => {
db.collection("posts").doc(id).get().then(doc => {
const newData = doc.data();
console.log(newData);
});
}, []);
return (
<div className="log">
<article className="log-details">
<div className="author-pic clearfix">
<img src={profile} alt="" />
</div>
<div className="log-preview">
<div class="cover"></div>
<h2 className="title clearfix">title here</h2>
<div className="details ">
<img src={One} alt="" />
<p className="essay">essay here</p>
</div>
</div>
</article>
</div>
)
To display the post Data use useState and set the postData with setPostData(newData). Then you can read the postData values with {postData.title} and {postData.essay} in the return statement.
Dont forget to import useState with import React, { useState, useEffect } from "react".
const { id } = useParams()
const [postData, setPostData] = useState("");
useEffect(() => {
db.collection("posts").doc(id).get().then(doc => {
const newData = doc.data();
setPostData(newData);
console.log(newData);
});
}, []);
return (
<div className="log">
<article className="log-details">
<div className="author-pic clearfix">
<img src={profile} alt="" />
</div>
<div className="log-preview">
<div class="cover"></div>
<h2 className="title clearfix">{postData && postData.title}</h2>
<div className="details ">
<img src={One} alt="" />
<p className="essay">{postData && postData.essay}</p>
</div>
</div>
</article>
</div>
)

React.js: posts.map is not a function

I'm getting this error when running my app and i don't know why!
i have this react component that's getting data from a djagno api that's consists of a title, body for the post, slug, image, date (day and month) and a category.
i have defined posts as an array but it's still giving me an error that's posts.map is not a function.
edit:i found out that the problem maybe cuz the data i'm getting from the api (res.data) which i console logged is an object that has the arrys i want to render
i hope someone can help me with this on cuz i have spent 3 days trying to figure out what's wrong with this code
import React, { useState, useEffect } from 'react';
import axios from 'axios';
import { Link } from 'react-router-dom'
const Post = () => {
const [posts, setPost] = useState([]);
useEffect(() => {
const fetchPost = async () => {
try {
const res = await axios.get(`${process.env.REACT_APP_API_URL}/api/post/`);
setPost(res.data);
console.log('data', res.data);
}
catch (err) {
}
}
fetchPost();
}, []);
const capitalizeFirstLetter = (word) => {
if (word)
return word.charAt(0).toUpperCase() + word.slice(1);
return '';
};
const getPost = () => {
let list = [];
let result = [];
posts.map(blogPost => {
return list.push(
<div className="row no-gutters border rounded overflow-hidden flex-md-row mb-4 shadow-sm h-md-250 position-relative">
<div className="col p-4 d-flex flex-column position-static">
<strong className="d-inline-block mb-2 text-primary">{capitalizeFirstLetter(blogPost.komite)}</strong>
<h3 className="mb-0">{blogPost.overskrift}</h3>
<div className="mb-1 text-muted">{blogPost.måned} {blogPost.dag}</div>
<Link to={`/post/${blogPost.slug}`} className="stretched-link">Les mer...</Link>
</div>
<div className="col-auto d-none d-lg-block">
<img width='200' height='250' src={blogPost.bilde} alt='bilde' />
</div>
</div>
);
});
for (let i = 0; i < list.length; i += 2) {
result.push(
<div key={i} className='row mb-2'>
<div className='col-md-6'>
{list[i]}
</div>
<div className='col-md-6'>
{list[i+1] ? list[i+1] : null}
</div>
</div>
)
}
return result;
};
return (
<div className='container mt-3'>
<div className="nav-scroller py-1 mb-2">
<nav className="nav d-flex justify-content-between">
<Link className="p-2 text-muted" to='/komite/aktulet'>Aktulet</Link>
<Link className="p-2 text-muted" to='/komite/upop'>Upop</Link>
<Link className="p-2 text-muted" to='/komite/musikk'>Musikk</Link>
<Link className="p-2 text-muted" to='/komite/fest'>Fest</Link>
<Link className="p-2 text-muted" to='/komite/kultur'>Kultur</Link>
<Link className="p-2 text-muted" to='/komite/debatt'>Debatt</Link>
<Link className="p-2 text-muted" to='/komite/okonomi'>Økonomi</Link>
<Link className="p-2 text-muted" to='/komite/pr'>PR</Link>
</nav>
</div>
{getPost()}
</div>
);
};
export default Post;
I didn't have a chance to test, but I think you may be getting this because there is no guarantee that the posts state has data when the rendering happens. You are calling the API but the rendering happens before the data is available.
One suggestion for loading data from an API like this is to use a loading/isLoaded state as well, and render conditionally to avoid these errors:
const [isLoaded, setIsLoaded] = useState(false);
And then when you get the data from the API:
setIsLoaded(true);
Finally, in your rendering code:
if ( isLoaded ) {
return ...
} else {
return null
}
posts should be accessed from setPost, which is what you're declaring in your hook.
You're currently calling it from getPost, which shouldn't be able to access posts.
I might be wrong as I'm new to hooks, but I think that's why it's not working.

Resources