Problem with array - Cannot read property 'map' of undefined - reactjs

I'm trying to do a Netflix clone using React but I've gotten this error and I'm not sure where the error is.
import React, { useState, useEffect } from 'react';
import axios from "./axios"
import "./Row.css"
const base_url = "https://image.tmdb.org/t/p/original/"
function Row({ title, fetchUrl, isLargeRow }) {
const [movies, setMovies] = useState([]);
useEffect(() => {
async function fetchData() {
const request = await axios.get(fetchUrl);
setMovies(request.data.results);
return request;
}
fetchData();
}, [fetchUrl]);
console.table(movies);
return (
<div className="row">
<h2>{title}</h2>
<div className="row__posters">
{movies.map((movie) => (
<img
key={movie.id}
className={`row__poster ${isLargeRow && "row__posterLarge"}`}
src={`${base_url}${movie.poster_path}`}
alt={movie.name}
/>
))}
</div>
</div>
);
}
export default Row
The error I keep getting is

Related

I'm getting this error map is not a function error

This is my code:
import React, { useEffect, useState } from 'react'
import axios from 'axios'
import { useLocation } from 'react-router-dom'
import Button from 'react-bootstrap/esm/Button'
const BookingScreen = () => {
const [room, setRoom] = useState([])
const [loading, setLoading] = useState()
const location = useLocation()
const path = location.pathname.split("/",5)[4]
useEffect(() => {
fetchData()
},[])
const fetchData = async () => {
const res = await axios.get("http://localhost:5000/api/room/" + path)
setRoom(res.data)
console.log(res.data)
setLoading(false)
}
const singleRoom = room.map((item) => {
return (
<div key={item._id} >
<div className="row justify-content-md-center mt-4 ">
<div className="col-md-6">
<img src={item.imageUrl
[0]
} alt="singleRoom" />
</div>
<div className="col-md-4">
<h2>{item.name}</h2>
<p>{item.desc}</p>
<p>Category : {item.categoy}</p>
<Button variant="secondary">
Book Now </Button>
</div>
</div>
</div>
)
})
return (
<>
{loading ? <h1>Loading ...</h1> : singleRoom}
</>
)
}
export default BookingScreen
I'm trying to populate the list singleRoom but it keeps saying map is not a function when I console data I'm getting everything and after that, I used setRoom hook to set the data, but somehow it's empty.
Things i would say, is that if the data returns as an array then its fine, otherwise you'll need to change your logic of return.
import React, { useEffect, useState } from 'react'
import axios from 'axios'
import { useLocation } from 'react-router-dom'
import Button from 'react-bootstrap/esm/Button'
const BookingScreen = () => {
const [room, setRoom] = useState([])
const [loading, setLoading] = useState(true) // set to true by default
const location = useLocation()
useEffect(() => {
fetchData()
}, [])
const fetchData = async () => {
const path = location.pathname.split("/", 5)[4]
setLoading(true)
try {
const res = await axios.get(`http://localhost:5000/api/room/${path}`)
if (res.data) {
setRoom(res.data); // does this actually return an array?
setLoading(false)
} else {
setRoom([]) // force back an empty array if data wasn't returned
setLoading(false)
}
} catch (err) {
setRoom([]) // set back to empty
setLoading(false)
// I'd usually also do an error state here.
}
}
const singleRoom = room.length > 0 ? room.map(({ _id, imageUrl, name, desc, categoy }) => (
<div key={_id} >
<div className="row justify-content-md-center mt-4 ">
<div className="col-md-6">
<img src={imageUrl
[0]
} alt="singleRoom" />
</div>
<div className="col-md-4">
<h2>{name}</h2>
<p>{desc}</p>
<p>Category : {categoy}</p>
<Button variant="secondary">
Book Now </Button>
</div>
</div>
</div>
)
) : <div>No room data found</div>
return (
<>
{loading ? <h1>Loading ...</h1> : singleRoom}
</>
)
}
export default BookingScreen

Unexpected token < in JSON at position 0 while trying to make link dynamic

I have checked in case there is an error or typo. I don't know if it is my res.json() file that is causing it.
I used usefetch to also import data from the API. so I had to pass it as JSON.
now I want to make each blog link dynamic.
my usefetch.js file
import { useState, useEffect} from 'react';
const useFetch = (url) =>{
const [data, setData] = useState(null);
const [error, setError] = useState(null);
useEffect( ()=>{
fetch(url)
.then(res =>{
if (!res.ok){
throw Error('could not fetch data');
}
return res.json();
})
.then(data=>{
setData(data.blogs);
setError(null);
})
.catch(err =>{
setError(err.message);
})
},
[url]);
return { data, error }
}
export default useFetch;
this is where I am getting the error. the link is correct.
BlogDetails.js file
import { useParams } from "react-router-dom";
import useFetch from "./useFetch";
const BlogDetails = () => {
const { id } = useParams()
const { data: blog, error} = useFetch('http://localhost:3000/blog/' + id);
return (
<div className="blog-details">
{error && <div>{error}</div>}
{ blog && (
<article>
<h2> {blog.title} </h2>
<p>by {blog.author}</p>
<div> {blog.body} </div>
</article>
)}
</div>
where i fetched my data from api
home.js file
//import { useState, useEffect } from 'react';
import Bloglist from './BlogList';
import useFetch from './useFetch';
const Home = () =>{
const { data: blogs, error } = useFetch("http://localhost/blogphpapi/views/getapi.views.php");
return(
<div className="home">
{error && <div>{error}</div>}
<h1>Home page content</h1>
{// {isPending && <div>Loading ...</div>}
} {blogs && <Bloglist blogs={blogs} title='Recent Updates' />}
</div>
);
}
export default Home;

React Responsive Carousel - Cannot read properties of null (reading 'type')

I try to implement react-responsive-carousel.
It works with static links but when i try to get the data from my db im getting error.
I tried to test if i get my link with console.log(imagemap) and it works fine.
Im getting: ['https://www.top-magazin-frankfurt.de/wp-content/up…1/12/Das-%E2%80%9EFranziska-im-Henninger-Turm.jpg', 'https://www.zeitlos-erding.de/wp-content/uploads/2…6/04/Zeitlos-Erding-Website-Restaurant-Bild-6.jpg']
But when i try to do it inside the carousel im getting this error: Cannot read properties of null (reading 'type')
import React, { useState, useEffect } from 'react';
import axios from 'axios';
import 'react-responsive-carousel/lib/styles/carousel.min.css'; // requires a loader
import { Carousel } from 'react-responsive-carousel';
const Ambience = () => {
const [images, setImages] = useState([]);
useEffect(() => {
const getImages = async () => {
const res = await axios.get('/api/galery');
setImages(res.data);
};
getImages();
}, []);
const imagemap = images.map((url) => {
return url.name;
});
console.log(imagemap);
return (
<div className='min-h-screen'>
<Carousel showArrows={true} showThumbs={true}>
{images.map((url, index) => {
<div key={index}>
<img src={url.name} />
</div>;
})}
</Carousel>
</div>
);
};
export default Ambience;
You forgot to write return in the Carousel.
<Carousel showArrows={true} showThumbs={true}>
{images.map((url, index) => {
return (
<div key={index}>
<img src={url.name} />
</div>);
})}
</Carousel>
import React, { useState, useEffect } from 'react';
import axios from 'axios';
import 'react-responsive-carousel/lib/styles/carousel.min.css'; // requires a loader
import { Carousel } from 'react-responsive-carousel';
interface IMAGES {
name: string;
}
const Ambience = () => {
const [images, setImages] = useState<IMAGES[]>([]);
useEffect(() => {
const getImages = async () => {
const res = await axios.get('/api/galery');
setImages(res.data);
};
getImages();
}, []);
return (
<div className='min-h-screen'>
<Carousel showArrows={true} showThumbs={true}>
{images.map((url, index) => (
<div key={index}>
<img src={url.name} />
</div>;
))}
</Carousel>
</div>
);
};
export default Ambience;

React useEffect for Loading Data

I'm learning React Hooks and I'm wondering what would be the most effective way to reload data while being "hook friendly".
I've identified 3 use cases (the latest apparently being the "more appropriate"
With Copied Code
//Example of Using useEffect Hooks by duplicating code
import React, {useState, useEffect} from 'react'
import axios from 'axios'
export default () => {
const [deals, setDeals] = useState([])
const [loading, setLoading] = useState(false)
useEffect(() => {
setLoading(true)
axios({
method: 'GET',
url: `http://localhost:1338/deals`
}).then(res => {
setDeals(res.data)
setLoading(false)
})
}, [setDeals])
return(
<div className="Deals">
{loading &&
<p>It's loading</p>
}
{!loading &&
<>
{deals.map((deal, i) => (
<div key={i} className="Deal Note">
{deal.label}
</div>
))}
</>
}
<button onClick={() => {
setLoading(true)
axios({
method: 'GET',
url: `http://localhost:1338/deals`
}).then(res => {
setDeals(res.data)
setLoading(false)
}).catch(res => {
setDeals([{label: 1, label: 2}])
setLoading(false)
})
}}>Fetch Again</button>
</div>
)
}
By Passing Hooks inside an external function. Code reuse - using hooks inside another function
I'm understanding this is not "the way" to use hooks although this was my first go-to solution
//Example of Using useEffect Hooks by feeding hooks to external function
import React, {useState, useEffect} from 'react'
import axios from 'axios'
const usefetchMore = (setDeals, setLoading) => {
console.log("usefetchMore")
setLoading(true)
axios({
method: 'GET',
url: `http://localhost:1338/deals`
}).then(res => {
setDeals(res.data)
setLoading(false)
})
}
export default () => {
const [deals, setDeals] = useState([])
const [loading, setLoading] = useState(false)
useEffect(() => {
usefetchMore(setDeals, setLoading)
}, [setDeals])
return(
<div className="Deals">
{loading &&
<p>It's loading</p>
}
{!loading &&
<>
{deals.map((deal, i) => (
<div key={i} className="Deal Note">
{deal.label}
</div>
))}
</>
}
<button onClick={() => usefetchMore(setDeals, setLoading)}>Fetch Again</button>
</div>
)
}
This one seem to be "the proper way of doing it" and is based on having useEffect re-triggered because it's listening to the changes on the reload variable which is there just to re-trigger it.
//Example of Using useEffect Hooks with variable to re-trigger useEffect
import React, {useState, useEffect} from 'react'
import axios from 'axios'
/* DOESN't WORK */
export default () => {
const [deals, setDeals] = useState([])
const [loading, setLoading] = useState(false)
const [reload, setReload] = useState(0)
useEffect(() => {
console.log("Deal4.useEffect")
setLoading(true)
axios({
method: 'GET',
url: `http://localhost:1338/deals`
}).then(res => {
setDeals(res.data)
setLoading(false)
})
}, [setDeals, reload])
return(
<div className="Deals">
{loading &&
<p>It's loading</p>
}
{!loading &&
<>
{deals.map((deal, i) => (
<div key={i} className="Deal Note">
{deal.label}
</div>
))}
</>
}
<button onClick={() => {
setReload(reload + 1)
}}>Fetch Again</button>
</div>
)
}
My question is: If I were to build a component that shows loading and allows to refresh itself, which way would be the proper way to write it with "React hooks"?
Create a component in /src/ called Photos.js and give it a basic list:
import React from "react";
import { useFetch } from "./hooks";
function Photos() {
const [data, loading] = useFetch(
"https://jsonplaceholder.typicode.com/photos?albumId=1"
);
return (
<>
<h1>Photos</h1>
{loading ? (
"Loading..."
) : (
<ul>
{data.map(({ id, title, url }) => (
<li key={`photo-${id}`}>
<img alt={title} src={url} />
</li>
))}
</ul>
)}
</>
);
}
export default Photos;
Now we need a Hook! Create a file in the same directory called hooks.js and fill it with this:
import { useState, useEffect } from "react";
function useFetch(url) {
const [data, setData] = useState([]);
const [loading, setLoading] = useState(true);
async function fetchUrl() {
const response = await fetch(url);
const json = await response.json();
setData(json);
setLoading(false);
}
useEffect(() => {
fetchUrl();
}, []);
return [data, loading];
}
export { useFetch };
Import the Photos component into App.js and yarn start. Done!

React Component State and API fetch

I have been studying React for past few days. In my blog project, I am using Axios to get data from API. Here is my component:
import React, { useState, useEffect } from "react";
import axios from "axios";
import { apiConstants } from "../../constants";
import SinglePost from "./SinglePost";
const PostContent = props => {
const {
match: { params }
} = props;
const [post, setPost] = useState({});
useEffect(() => {
axios
.get(apiConstants.singlePost + `${params.post_slug}`)
.then(function(response) {
setPost(response.data);
})
.finally(function() {
// always executed
});
}, []);
return (
<React.Fragment>
<div className="container">
<div className="row">
<div className="col-lg-8 col-md-10 mx-auto">
<SinglePost post={post} />
</div>
</div>
</div>
</React.Fragment>
);
};
export default PostContent;
Above code works fine though I noticed the first time it tries to render the component with empty ({}) post object (Due to the default value in 'useState'). However, it causes issues in my child component cause it is directly using 'post' object properties. For example: 'post.content'. Here is my 'SinglePost' component's code:
const SinglePost = props => {
const { post } = props;
console.log(post);
return (
<div>{post.content}</div>
);
};
It returns undefined error for {post.content} object. To resolve the issue I had to use something like {post && <SinglePost post={post} />}, But it doesn't feel right. Is there any better way to handle such scenarios.
Consider revising the PostContent component's rendering logic to account for the case where no post data is present during the network request.
You could for instance initialise your post state to null, and then update the rendered result to prevent the SinglePost component from being rendered while post is null.
Once the network request is completed and the post state is set, the component will re-render causing SinglePost to be rendered with the non-null post state:
const PostContent = props => {
const {
match: { params }
} = props;
const [post, setPost] = useState(null); /* Update: "Initial data" set to null */
useEffect(() => {
axios
.get(apiConstants.singlePost + `${params.post_slug}`)
.then(function(response) {
setPost(response.data);
})
.finally(function() {
// always executed
});
}, []);
return (
{ /* <React.Fragment> Not needed */ }
<div className="container">
<div className="row">
<div className="col-lg-8 col-md-10 mx-auto">
{ /* Update: If post is null, assume network request is
still in progress so rendering loading message instead
of single post component */ }
{ post === null ? <p>Loading</p> : <SinglePost post={post} /> }
</div>
</div>
</div>
);
};
export default PostContent;
This approach is generally the simplest and more common pattern to async requests and rendering.
There are some other approaches that you might want to consider such as this declarative approach to data fetching, or the use of Reacts suspense feature for asynchronous rendering
You need to make post's initial value an array:
import React, { useState, useEffect } from "react";
import axios from "axios";
import { apiConstants } from "../../constants";
import SinglePost from "./SinglePost";
const PostContent = props => {
const {
match: { params }
} = props;
const [post, setPost] = useState([]);
useEffect(() => {
axios
.get(apiConstants.singlePost + `${params.post_slug}`)
.then(function(response) {
setPost(response.data);
})
.finally(function() {
// always executed
});
}, []);
return (
<React.Fragment>
<div className="container">
<div className="row">
<div className="col-lg-8 col-md-10 mx-auto">
<SinglePost post={post} />
</div>
</div>
</div>
</React.Fragment>
);
};
export default PostContent;
and in single post map through the array
const SinglePost = props => {
const { post } = props;
console.log(post);
return (
<div>
{post.map((post, key) => (
<div key={key}>{post.content}</div>
))}
</div>
);
};
You can do something like
import React, { useState, useEffect } from "react";
import axios from "axios";
import { apiConstants } from "../../constants";
import SinglePost from "./SinglePost";
const PostContent = props => {
const {
match: { params }
} = props;
const [posts, setPosts] = useState([]);
useEffect(() => {
axios
.get(apiConstants.singlePost + `${params.post_slug}`)
.then(function(response) {
setPosts(response.data);
})
.finally(function() {
// always executed
});
}, []);
return (
<React.Fragment>
<div className="container">
<div className="row">
<div className="col-lg-8 col-md-10 mx-auto">
{this.state.posts.map(post => (<SinglePost post={post} key={post.id} />))
</div>
</div>
</div>
</React.Fragment>
);
};
export default PostContent;

Resources