React.js: posts.map is not a function - reactjs

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.

Related

How to pass props to a component on clicking button?

I have displayed all the anime images from api, now I want if any anime result is clicked then it should open details for that particular anime. I have created component Details where I want to send details of anime.
how can I send details of anime to the component Details ?
Here is my code:
import { useEffect, useState } from 'react';
import './CSS/style.css';
import Details from './components/Details';
function App() {
const [user, setUser] = useState([])
const getUsers = async () =>{
const response = await fetch('https://ghibliapi.herokuapp.com/films')
setUser(await response.json());
}
useEffect(() => {
getUsers();
}, []);
const getDetail = (e) =>{
// what should I write here to pass props on component < Details />
console.log(e)
}
return (
<>
<h2>Anime World</h2>
<div className="container-fluid mt-5">
<div className="row text-center">
{
user.map((curElem) => {
return (
<div className="col-10 col-md-4 mt-5" key={curElem.id} >
<div className="card">
<img src={curElem.image} className="card-img-top imageSize" alt="..."/>
<div className="card-body">
<h5 className="card-title">{curElem.title} </h5>
<button onClick={getDetail} >Get Detail</button>
</div>
</div>
</div>
)
})
}
</div>
</div>
</>
);
}
export default App;
Dummy values are given to component Details right now, I have to get correct value from props.
import React from 'react';
import './details.css';
function Details() {
return (
<>
<h2>Information of Anime</h2>
<div className="container-fluid mt-5">
<div className="row text-center">
<div className="col-10 col-md-8 mx-auto" >
<div className="card box">
<img src= '...' className="card-img-top imageSize" alt="..."/>
<div className="card-body">
<div className='details'>
<h5><span>Title:</span> Title</h5>
<h5><span>Original Title:</span> Original Title</h5>
<h5><span>Director:</span> Director</h5>
<h5><span>Producer:</span> Producer</h5>
<h5><span>Release Date:</span> date</h5>
<h5><span>Running time:</span> time</h5>
<h5><span>Description:</span> <p> Description</p></h5>
</div>
</div>
</div>
</div>
</div>
</div>
</>
)
}
export default Details;
I'm going to assume that the list you receive from the API is the list of each anime, and when you click you want to render the selected anime using the Details component. If that's the case this is my approach
import { useEffect, useState } from 'react';
import './CSS/style.css';
import Details from './components/Details';
function App() {
const [user, setUser] = useState([]);
const [anime, setAnime] = useState(null);
const getUsers = async () =>{
const response = await fetch('https://ghibliapi.herokuapp.com/films');
setUser(await response.json());
};
useEffect(() => {
getUsers();
}, []);
const getDetail = (anime) =>{
setAnime(anime);
};
return (
<>
<h2>Anime World</h2>
<div className="container-fluid mt-5">
<div className="row text-center">
{user.map((elem) => (
<div className="col-10 col-md-4 mt-5" key={curElem.id}>
<div className="card">
<img src={elem.image} className="card-img-top imageSize" alt="..."/>
<div className="card-body">
<h5 className="card-title">{elem.title} </h5>
<button onClick={() => getDetail(elem)} >Get Detail</button>
</div>
</div>
</div>
))}
</div>
</div>
{anime && <Details {...anime} />}
</>
);
}
export default App;
So basically what I'm doing here is rendering <Details /> only when an anime element is in state. If it's null it won't render the component.
Secondly I'm spreading the selected element into the Details component, so that inside the component you can access each property like this:
import React from 'react';
import './details.css';
function Details(props) {
const { title } = props; // each prop is each property of the selected anime
return (
<>
<h2>Information of Anime</h2>
<div className="container-fluid mt-5">
<div className="row text-center">
<div className="col-10 col-md-8 mx-auto" >
<div className="card box">
<img src= '...' className="card-img-top imageSize" alt="..."/>
<div className="card-body">
<div className='details'>
<h5><span>Title:</span> {title}</h5>
<h5><span>Original Title:</span> Original Title</h5>
<h5><span>Director:</span> Director</h5>
<h5><span>Producer:</span> Producer</h5>
<h5><span>Release Date:</span> date</h5>
<h5><span>Running time:</span> time</h5>
<h5><span>Description:</span> <p> Description</p></h5>
</div>
</div>
</div>
</div>
</div>
</div>
</>
)
}
export default Details;

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>
)}

Why is my fetched data not appearing in my React hooks component?

I am trying to load data into my component for it to be displayed. I thought the issue was that I wasn't using async/await for the fetch, but even after adding that it still is not loading. I am logging out the "offerings" and it is just showing the empty array. How do I keep the component from rendering until after the data is loaded??
Thanks in advance!
const [offerings, setOfferings] = useState([]);
const loadData = async () => {
const res = await fetch(`http://52.207.83.69` + `${CRUD_OFFERING}`);
setOfferings(await res.json());
console.log(offerings, 'offerings')
};
useEffect(async () => {
navbarToggle();
await loadData();
}, []);
const dispatch = useDispatch();
const modalState = useSelector((state) => state.modal);
const modalToggle = () => {
dispatch({
type: MODAL_TOGGLE,
payload: !modalState.show,
});
ga.event("navbar_requestdemo_clicked");
};
const navbarOpenState = useSelector((state) => state.navbar);
const navbarToggle = () => {
if (!navbarOpenState.open) return;
dispatch({
type: NAVBAR_OPEN,
payload: false,
});
};
return (
<div
className="d-flex justify-content-center align-items-center bg-color-white fc-px-15"
onClick={navbarToggle}
>
<div className={homeStyles["padded-body"] + " col-11 p-0"}>
<div className=" position-relative bg-color-white">
<div className={homeStyles["img-holder"]}></div>
<div className="col-12 column position-absolute top-0 d-flex justify-content-center">
<div className="col-lg-6 col-12 fc-mt-2">
<SearchBar />
</div>
</div>
<div className="position-absolute top-50 translateY-middle">
<div className="position-relative">
<h1 className={`${homeStyles["hero-text"]} font-weight-bolder`}>
Building
<br />
Meaningful
<br />
Engagement
</h1>
<button
className="btn btn-primary-round mt-3 px-3 py-2"
onClick={() => {
modalToggle();
}}
>
Request access
</button>
</div>
</div>
</div>
<div
id={homeStyles["discover-section"]}
className="d-flex justify-content-center align-items-center"
>
<div className="col-12 column">
<h4 className="font-weight-bold">Discover</h4>
<div
id={homeStyles["offer-section"]}
className="row justify-content-center align-items-center"
>
{!offerings?.length &&
<h4 className="text-center">There are no active offerings.</h4>
}
</div>
<OfferingCarousal
offeringsList={offerings}
name={"Offerings"}
/>
<div id={homeStyles["consultancy-section"]} className="">
<div className="row">
<div
className="d-flex justify-content-center align-items-center col-lg-6 col-12 px-0 mt-3 mb-4"
id={homeStyles["consultancy-div"]}
>
<div className="col-12 column p-5">
<h1 className="font-weight-bold">Add your consultancy</h1>
<h5 className="mt-4">
Reach more people and organizations
</h5>
<Link href="/consultancies">
<button className="btn btn-primary-round mt-4">
Learn more
</button>
</Link>
</div>
</div>
<div className="col-lg-6 col-12 px-0">
<img
src="/images/Rachael_glasses_home_page.jpg"
id={homeStyles["consultant-img"]}
className="mt-3"
/>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
);
};
export default HomeNew;
You can check if the data is present before you consume the data.
const [offerings, setOfferings] = useState([]);
const loadData = async () => {
const res = await fetch(`http://52.207.83.69` + `${CRUD_OFFERING}`);
setOfferings(res.json());
console.log(res, 'offerings')
};
useEffect(() => {
navbarToggle();
loadData(); // await has no affect inside useEffect for top level functions
}, []);
// removed internal code for clarity
const dispatch = useDispatch(...yourCode);
const modalState = useSelector(...yourCode);
const modalToggle = () => {...yourCode};
const navbarOpenState = useSelector(...yourCode);
const navbarToggle = () => {...yourCode};
// check after the hooks and before the consuming the data
if(!offerings && !offerings.length) return <>No offerings</>;
return <div>your side nav</div>;
};
It's also good practice to catch asynchronous errors as they occur to prevent your a single component form breaking your whole app. You can also take advantage of the try...catch and put in loading and error states too.
const [loading, setLoading] = useState(false);
const [error, setError] = useState(false);
const [offerings, setOfferings] = useState([]);
const loadData = async () => {
try {
setError(false);
setLoading(true);
const res = await fetch(`http://52.207.83.69` + `${CRUD_OFFERING}`);
setOfferings(res.json());
} catch (e){
setError(true)
} finally {
setLoading(false);
}
};
// other code from above
if(error) return <>error</>;
if(loading) return <>loading</>;
if(!offerings && !offerings.length) return <>No offerings</>;
return <div>your side nav</div>;
};
async function can't be put in the useEffect hook directly.
https://prnt.sc/1lu7vdc
It can be like this.
useEffect(() => {
...
(async ()=>{
await loadData()
})();
}, []);
But in your case, I think you don't need to wait until loadData function is executed.
Just make sure you handle exceptions on the rendering for Empty data.

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>
)

Passing methods between Functional components in react

I have 2 components as below. When I try to pass a method (increment) from the component 'CartList' to 'CartItem' it says increment is undefined. The error occurs when I click on the button (Pointed in the below code). How can I solve this error?
Parent
import React, {Component} from 'react';
import CartItem from './CartItem';
import {connect} from "react-redux";
import Axios from "axios";
const mapStateToProps = ({ session}) => ({
session
});
const CartList = ({session, ...props}) => {
const cart = props.cart;
const increment = (productId) => {
const item = {
userId : session.userId,
productId: productId
};
Axios.post('http://localhost:5000/api/cart/increment', item)
.then(res=>{
if(res.status === 200){
console.log('Incremented');
}
})
};
return (
<div className="container-fluid">
{cart.map(item => {
return <CartItem key = {item.id} item={item} increment={increment}/>
})}
</div>
);
};
export default connect(
mapStateToProps
)(CartList);
Child
import React from 'react';
import {connect} from "react-redux";
const mapStateToProps = ({ session}) => ({
session
});
const CartItem = ({session ,...props}) => {
const {id,name, price, quantity} = props.item;
const {increment} = props.increment;
return (
<div className="row my-2 text-capitalize text-center">
<div className="col-10 mx-auto col-lg-2">
<img style={{width: '5rem', height: '5rem'}} className="img-fluid" alt="product "/>
</div>
<div className="col-10 mx-auto col-lg-2">
<span className="d-lg-none">Product: </span>{name}
</div>
<div className="col-10 mx-auto col-lg-2">
<span className="d-lg-none">Price: </span>{price}
</div>
<div className="col-10 mx-auto col-lg-2 my-2 my-lg-0">
<div className="d-flex justify-content-center">
<div>
<span className="btn btn-black mx-1" >-</span>
<span className="btn btn-black mx-1">{quantity}</span>
<span className="btn btn-black mx-1" onClick={() => increment(id)}>+</span> //<- Error occurs if I click on this button
</div>
</div>
</div>
<div className="col-10 mx-auto col-lg-2">
<div className="cart-icon" >
<i className="fas fa-trash"/>
</div>
</div>
<div className="col-10 mx-auto col-lg-2">
<srong>Total: ${50}</srong>
</div>
</div>
);
};
export default connect(
mapStateToProps
)(CartItem);
I tried implementing the function directly in the child component it is working fine. This method is responsible for incrementing the quantity of a product in the database(MongoDB). But updated value does not display. Because of that I implemented the 'increment' function within the parent component
The issue is this line:
const {increment} = props.increment;
That is trying to access props.increment.increment, which is undefined. You either meant to do
const increment = props.increment;
or
const {increment} = props;
Hi Please replace this line
Because when you destructuring props you don't need map key from props
for better understanding console your props or have a look at this document.
https://medium.com/#lcriswell/destructuring-props-in-react-b1c295005ce0
const {increment} = props.increment;
instead of
const {increment} = props;
I hope it works.
Thanks

Resources