I'm trying to display data from the OMdb API, but every time I try using my method nothing works.
I want to display the movie posters onto a slider using Spline.js, I was able to successfully do so whenever I manually put in the JSON data into the state but now I want to get the data from the API and I'm coming across this props.movie.map is not a function error all the way in an external component.
Heres the project on CodeSandbox just in case
https://codesandbox.io/s/github/JojoDuke/reactmoviesapp?file=/src/App.js
App.js
/* eslint-disable react-hooks/exhaustive-deps */
import React, { useState, useEffect } from 'react';
import "bootstrap/dist/css/bootstrap.min.css";
import "./App.css"
import MoviesList from "./components/MoviesList";
import ListHeading from './components/ListHeading';
import { SearchBox } from './components/SearchBox';
import AddFavourites from './components/AddFavourites';
import RemoveFavourites from './components/RemoveFavourites';
import MainMovie from './components/MainMovie';
import Navbar from './components/Navbar';
import Footer from './components/Footer';
const App = () => {
const [movies, setMovies] = useState([]);
const [searchValue, setSearchValue] = useState("");
const [favourites, setFavourites] = useState([]);
// Backup
// const getMovie = async () => {
// const url = 'http://www.omdbapi.com/?i=tt3896198&apikey=ce990560';
// const res = await fetch(url);
// const data = await res.json();
// const responseJson = JSON.parse(data);
// setMovies(responseJson);
// }
const API_KEY = "91d62f4";
const url = `http://www.omdbapi.com/?i=tt3896198&apikey=${API_KEY}`;
const getMovies = async () => {
try {
const response = await fetch(url);
const data = await response.json()
setMovies(data);
} catch (e) {
console.error(e.toString);
}
}
// FUNCTIONS
useEffect(() => {
getMovies();
}, []);
useEffect(() => {
const movieFavourites = JSON.parse(
localStorage.getItem('react-movie-app-favourites')
);
if (movieFavourites) {
setFavourites(movieFavourites);
}
}, []);
const saveToLocalStorage = (items) => {
localStorage.setItem('react-movie-app-favourites', JSON.stringify(items));
}
const addFavouriteMovie = (movie) => {
const newFavouriteList = [...favourites, movie];
setFavourites(newFavouriteList);
saveToLocalStorage(newFavouriteList);
}
const removeFavouriteMovie = (movie) => {
const newFavouriteList = favourites.filter((favourite) => favourite.imdbID !== movie.imdbID);
setFavourites(newFavouriteList);
saveToLocalStorage(newFavouriteList);
}
// FUNCTIONS CLOSE
return (
<div>
{/* Navigation Bar */}
<div>
<Navbar />
</div>
<div className="row d-flex align-items-center mb-5">
{/* Main Movie Area */}
<MainMovie/>
{/* <SearchBox
searchValue={searchValue}
setSearchValue={setSearchValue}/> */}
</div>
{/* Movies List */}
<ListHeading heading="Trending" />
<div>
<MoviesList
movies={movies}
handleFavouritesClick={addFavouriteMovie}
favouriteComponent={AddFavourites}/>
</div>
{/* List 2 */}
<div className="row d-flex align-items-center mt-4 mb-4">
<ListHeading heading="Cinetime Originals" />
</div>
<div>
<MoviesList
movies={movies}
handleFavouritesClick={addFavouriteMovie}
favouriteComponent={AddFavourites}/>
</div>
{/* List 3 */}
<div className="row d-flex align-items-center mt-4 mb-4">
<ListHeading heading="Classics" />
</div>
<div>
<MoviesList
movies={movies}
handleFavouritesClick={addFavouriteMovie}
favouriteComponent={AddFavourites}/>
</div>
<Footer />
</div>
);
};
export default App;
MoviesList.js(where I'm getting the error)
import React from 'react';
import { Splide, SplideSlide } from '#splidejs/react-splide';
//import '#splidejs/splide/dist/css/themes/splide-default.min.css';
const MoviesList = (props) => {
//const FavouriteComponent = props.favouriteComponent;
const movieSplide = props.movies.map((movie, index) => {
return(
<SplideSlide>
<div className="movie-div">
<div className="overlay"></div>
<img
className="movie-item shadow"
src={movie.Poster}
alt='movie'></img>
</div>
</SplideSlide>
);
});
return(
<Splide options={{
rewind: false,
autoWidth: true,
perPage: 6,
perMove: 2,
pagination: false,
gap: '1em',
focus: 'center',
type: 'slide',
easing: 'ease',
arrows: true
}}>
{movieSplide}
</Splide>
);
};
export default MoviesList;
Related
I have a component NFTCard as below, that displays images as card
import React, {useCallback, useState} from "react";
const NFTCard = ({nft}) => {
const [image, setImage] = useState(null);
const handleImage = useCallback(event => {
setImage(event.target.src)
console.log(event.target.src)
console.log(image)
},[image])
return(
//Wrapping the image in a card
<div className="rounded overflow-hidden shadow-lg">
<img className= "object-contain h-50 w-50"
src={nft.meta.image.url.ORIGINAL}
alt={nft.meta.name}
onClick= {handleImage}
/>
<div className="px-1 py-1">
<div className="font-bold text-xs mb-0">{nft.meta.name}</div>
</div>
</div>
)
}
export default NFTCard
What I am trying to do here is whenever an image on a card is clicked, I wish to display it again as an enlarged form in another div element
Here is my main page where i am displaying the image
import Link from 'next/link';
import { useWeb3Context } from '../../context'
import { Web3Address, Web3Button } from '../../components';
import React, { useEffect, useState } from 'react';
import NFTCard from '#/components/NFTCard';
import {useRouter} from 'next/router';
//render only the web3 button if the user is not connected to the web3 provider
const renderNotConnectedContainer = () => (
<div>
<p>Connect Wallet to continue</p>
</div>
);
export const ChooseProductView = () => {
const router = useRouter();
const { address } = useWeb3Context()
const [nfts, setNfts] = useState([]);
// Function to get the details of the NFTs held in the Wallet
const fetchNFTs = async () =>
{
const accounts = await window.ethereum.request({method: 'eth_requestAccounts'});
const response = await fetch(`https://ethereum-api.rarible.org/v0.1/nft/items/byOwner?owner=${accounts[0]}&size=100`)
//limiting the size to 100 so that there is not too much data to fetch
const data = await response.json()
setNfts(data.items)
console.log(data.items)
}
//creating a useEffect to fetch the NFTs details which is an async function
useEffect(() => {
const getNFTs = async () => {
await fetchNFTs()
}
getNFTs()
}, [])
if(!address){
return renderNotConnectedContainer()
}
else{
//rendering the NFTs details via the NFTContainer component
return(
<div className="flex flex-row">
<div className="basis-1/4"> {/*Splitting the screen into 3 parts*/}
<br/>
<div className = "container mx-auto">
<div className="grid grid-cols-2 gap-2 auto-rows-max">
{/*Calling the NFTCard component to render the NFTs details*/}
{nfts.map((nft, index) => {
return <NFTCard nft={nft} key= {index}/>
})
}
</div>
</div>
</div>
<div className="basis-1/2">
<div className="max-w-lg container mx-auto">
<img className="w-full" src={`${router.basePath}/assets/images/Hoodie black label.jpg`} alt="Empty Hoodie"/>
<div className="px-4 py-6">
</div>
</div>
</div>
<div className="basis-1/4">
<Web3Address/>
</div>
</div>
)
}
};
How do i fetch the image url stored in NFTCard with use state into a div element in ChooseProductView?
Thanks a lot in advance
I'm trying to make a FAQ of sorts, right now I have it as a search bar but I'm having a hard time sending a value that I want the videos to populate with. I want the user to have the option to click on the button, and that specific button have the data of "How to find a queen" and send that automaitcally to the iframe player. Any pointers on how to achieve this? As I have it right now, my handleSubmit populates the search bar.
SearchBar.jsx
import React, { useState } from 'react';
import "./SearchBar.css";
const SearchBar = (props) => {
const [searchRequest, setSearchRequest] = useState('');
const handleSubmit = (event) => {
event.preventDefault();
props.getSearchResults(searchRequest);
setSearchRequest('What Does a Queen Bee look like?');
}
return (
<div className='search-contain'>
<form className='search-form-contain' onSubmit={handleSubmit}>
<label className='search-label'>Search:</label>
<input type='text' placeholder="Search for a video..." className='search-input' value={searchRequest} onChange ={(event) => setSearchRequest(event.target.value)} />
<button className='search-button'>Search</button>
</form>
</div>
);
}
export default SearchBar;```
import React from "react";
import "./VideoPlayer.css";
const VideoPlayer = (props) => {
return (
<div>
<iframe
id="ytplayer"
title="MyPlayer"
type="text/html"
width="640"
height="360"
src={`https://www.youtube.com/embed/${props.videoId}?autoplay=1&origin=http://example.com`}
frameBorder="0">
</iframe>
<div className="video-details">
<h3>{props.title}</h3>
<p>{props.description}</p>
</div>
<div className="video-details">
</div>
<div className="flex-container">
{props.relatedVideos.map((video, index) => {
if(video.snippet){
return (
<div key={index} className="flex-item">
<div>
<img src={video.snippet.thumbnails.medium.url} alt="" />
</div>
<div>
<h6 >{video.snippet.title}</h6>
</div>
</div>
);
} else {
return null;
}
})}
</div>
</div>
);
}
export default VideoPlayer;
VideoPage.js
import React, {useEffect, useState } from "react";
import { Link } from "react-router-dom";
import "./VideoPage.css";
import SearchBar from "../../components/SearchBar/SearchBar";
import axios from 'axios'
import VideoPlayer from "../../components/VideoPlayer/VideoPlayer";
import { KEY } from "./../../localKey"
const VideoPage = () => {
const [searchResults, setSearchResults] = useState('');
const [videoId, setVideoId] = useState("");
const [description, setDescription] = useState("");
const [title, setTitle] = useState("");
const [relatedVideos, setRelatedVideos] = useState([]);
useEffect(() => {
getSearchResults();
},[])
async function getSearchResults(searchTerm='Bees'){
let response = await axios.get(`https://www.googleapis.com/youtube/v3/search?part=snippet&q=${searchTerm}&type=video&maxResults=1&key=${KEY}`);
setVideoId(response.data.items[0].id.videoId)
setDescription(response.data.items[0].snippet.description)
setTitle(response.data.items[0].snippet.title)
setSearchResults(response.data.items)
console.log(response.data.items)
}
useEffect(() => {
const fetchRelatedVideos = async () => {
try {
let response = await axios.get(`https://www.googleapis.com/youtube/v3/search?key=${KEY}&part=snippet&maxResults=3&type=video&relatedToVideoId=${videoId}`, {
});
setRelatedVideos(response.data.items);
} catch (error) {
console.log(error.message);
}
};
fetchRelatedVideos();
}, [videoId]);
return (
<div>
<div className="video-reg-contain"></div>
<div><SearchBar getSearchResults={getSearchResults}/></div>
<div className = 'video-contain'>
<div className="video-container">
<div className='video-player'>
<VideoPlayer videoId={videoId}
description={description}
title={title}
relatedVideos={relatedVideos}/>
</div>
</div>
</div>
</div>
);
};
export default VideoPage;
I want to integrate a search functionality in my Next.js app which should look like this:
User types a keyword in searchBar which is inside of Header
After clicking on the search button the keyword should be passed on the SearchResult page, in which I load it dynamically into the youtube-search-api link
The structure looks like this:
Header.js (contains SearchBar component)
_app.js (contains Header and components)
SearchResults.js (inside pages folder, should fetch typed keyword from Header)
I tried it with zustand and it looks like this currently:
Header.js:
import SearchBar from "./SearchBar";
const Header = () => {
return (
<div className={styles.header}>
...
<SearchBar />
...
</div>
);
};
export default Header;
SearchBar.js:
import create from 'zustand';
import { useRouter } from 'next/router';
import Image from 'next/image';
import styles from '../styles/Header.module.scss';
import loupe from '../public/images/loupe.png';
const useStore = create((set) => ({
keyword: '',
setKeyword: (keyword) =>
set((state) => ({
...state,
keyword,
})),
}));
const SearchBar = () => {
const router = useRouter();
const keyword = useStore((state) => state.keyword);
const setKeyword = useStore((state) => state.setKeyword);
const handleClick = (e) => {
e.preventDefault();
router.push('/searchResults');
};
return (
<div className={styles.searchBar}>
<input
type='text'
value={keyword}
placeholder='Suche...'
onChange={(e) => setKeyword(e.target.value)}
/>
<button className={styles.searchBtn} type='submit' onClick={handleClick}>
<Image src={loupe} alt='' />
</button>
</div>
);
};
export default SearchBar;
_app.js:
import Header from '../components/Header';
function MyApp({ Component, pageProps }) {
return (
<>
<Header />
<Component {...pageProps} />
</>
);
}
export default MyApp;
and SearchResults.js:
import { fetchData } from '../lib/utils';
import Moment from 'react-moment';
import { Modal } from 'react-responsive-modal';
import ReactPlayer from 'react-player/youtube';
export default function SearchResults({ videos }) {
console.log(videos);
const [modalIsOpen, setModalIsOpen] = useState(false);
const [modalData, setModalData] = useState(null);
const videoURL = 'https://www.youtube.com/watch?v=' + modalData;
const sortedVids = videos
.sort((a, b) =>
Number(
new Date(b.snippet.videoPublishedAt) -
Number(new Date(a.snippet.videoPublishedAt))
)
)
.filter((vid) => vid.snippet.title.toLowerCase());
return (
<>
<div className={`${styles.playlist_container} ${styles.search}`}>
<div className={styles.main_container}>
<h1>Search results</h1>
{sortedVids
.filter((v) => v.snippet.title !== 'Private video')
.map((vid, id) => {
return (
<div className={styles.item_container}
key={id}>
<div className={styles.clip_container}>
<Image
className={styles.thumbnails}
src={vid.snippet.thumbnails.medium.url}
layout='fill'
objectFit='cover'
alt={vid.snippet.title}
/>
<button
className={styles.playBtn}
onClick={() => {
setModalData(vid.snippet.resourceId.videoId);
console.log(modalData);
setModalIsOpen(true);
}}
>
<Image src='/images/play.svg' width='60' height='60' />
</button>
</div>
<div className={styles.details_container}>
<h3>{vid.snippet.title}</h3>
</div>
</div>
);
})}
</div>
</div>
<div>
<Modal
open={modalIsOpen}
onClose={() => setModalIsOpen(false)}
center
classNames={{
overlay: 'customOverlay',
modal: 'customModal',
overlayAnimationIn: 'customEnterOverlayAnimation',
overlayAnimationOut: 'customLeaveOverlayAnimation',
modalAnimationIn: 'customEnterModalAnimation',
modalAnimationOut: 'customLeaveModalAnimation',
}}
animationDuration={800}
>
<ReactPlayer
playing={true}
url={videoURL}
width='100%'
height='calc(100vh - 100px)'
config={{
youtube: {
playerVars: {
autoplay: 1,
controls: 1,
},
},
}}
/>
</Modal>
</div>
<Footer />
</>
);
}
export async function getStaticProps() {
const keyword = useStore((state) => state.keyword);
const { YOUTUBE_KEY } = process.env;
const uploadsURL = `https://youtube.googleapis.com/youtube/v3/search?part=snippet&channelId=UCbqKKcML7P4b4BDhaqdh_DA&maxResults=50&key=${YOUTUBE_KEY}&q=${keyword}`;
async function getData() {
const uploadsData = fetchData(uploadsURL);
return {
videos: await uploadsData,
};
}
const { videos } = await getData();
return {
revalidate: 86400,
props: {
videos: videos.items,
},
};
}
Would someone please help me out by telling me what I did wrong and how it works in the right way? Thank you guys!!
Hi people Am new in react js, i have a problem in display data , in my application i fetched data but i couldn't be display in web page don't know where Am wrong please try to fix my error or tell me what should i do?
console data
https://ibb.co/1MfgDgW
Star.js
import Axios from 'axios';
import React, { useState, useEffect } from 'react';
import './Star.css';
import Planet from './Planet';
import People from './People';
const Star = () => {
const [search, setSearch] = useState('');
const [people, setPeople] = useState([]);
const [planet, setPlanet] = useState([]);
const onSubmit = (e) => {
e.preventDefault();
if (search === "") {
alert("please Enter some value");
}
}
useEffect(() => {
async function fetchPeople() {
const res = await Axios.get("https://swapi.dev/api/people/?format=json");
console.log(res.data.results);
setPeople(res.data.results);
}
async function fetchPlanet() {
const res = await Axios.get("https://swapi.dev/api/planets/?format=json");
console.log(res.data.results);
setPlanet(res.data.results);
}
fetchPeople();
fetchPlanet();
}, [])
// console.log("people", people);
// console.log("planet", planet);
return (
<div>
<div className='container'>
<h2>Star War </h2>
<div className='jumbotron'>
<input type="text"
className="form-control"
placeholder='Search...'
value={search}
onChange={(e) => setSearch(e.target.value)} />
<span><button className='btn btn-secondary' onClick={onSubmit}>Search</button></span>
</div>
<People people={people}/>
<Planet planet={planet}/>
</div>
</div>
)
}
export default Star;
People.js
import React from 'react';
const People = (props) => {
const { data } = props;
return (
<div className="row">
{data && data.map((people, i) => {
return (
<div className="col-md-3" key={i}>
<div className="card">
<div className="card-body">
<h4>{people.data.results[0].name}</h4>
</div>
</div>
</div>
)
})}
</div>
);
};
export default People;
Planet.js
import React from 'react';
const Planet = (props) => {
const { data } = props;
return (
<div className="row">
{data && data.map((planet, i) => {
return (
<div className="col-md-3" key={i}>
<div className="card">
<div className="card-body">
<h4>{planet.data.results[0].name}</h4>
</div>
</div>
</div>
)
})}
</div>
);
};
export default Planet;
App.js
This is the App.js file where i include my all components
import './App.css';
import Star from './Star';
import People from './People';
import Planet from './Planet';
function App(props) {
const { people, planet } = props;
return (
<div className="App">
<Star
people={people}
planet={planet}
/>
<People data={people} />
<Planet data={planet} />
</div>
);
}
export default App;
You pass people and planet as props, but using it as data prop:
<Planet planet={planet}/>
const Planet = (props) => {
// change to this, people too
const { planet } = props;
};
You're passing people and planet as props to App but you're performing the fetching in Star.js.
You might need to restructure your app so that data fetching is done by App and then pass down everything as props.
function App(props) {
const { people, planet } = props;
return (
<div className="App">
<Star people={people} planet={planet} />
<People data={people} />
<Planet data={planet} />
</div>
);
}
I am trying the send axios get request to server.js, which send a GET request to contentful website. I am getting no data in Home.js and getting following error in console. Could someone please help me to identify the issue here ?
I could see data displaying in setSearchResults while setting a break point, please refer screenshot attached.
Warning: Maximum update depth exceeded. This can happen when a
component calls setState inside useEffect, but useEffect either
doesn't have a dependency array, or one of the dependencies changes on
every render.
in Home (created by Context.Consumer)
in Route (at App.js:18)
in Switch (at App.js:17)
in Router (created by BrowserRouter)
in BrowserRouter (at App.js:15)
in App (at src/index.js:11)
in Router (created by BrowserRouter)
in BrowserRouter (at src/index.js:10)
Home.js
import React, { useRef, useState, useEffect, Component } from 'react';
import { usePosts } from "../custom-hooks/";
import Moment from 'moment';
import { Wave } from "react-animated-text";
import axios from "axios";
export default function Home() {
const [posts, isLoading] = usePosts();
const [searchTerm, setSearchTerm] = useState("");
const [searchResults, setSearchResults] = useState([]);
const [showColor, setShowColor] = useState("");
const [findTag, setFindTag] = useState("");
//const isMounted = useRef(false);
/* In the Home tab, system displays all the published blogs from contentful website.
We can search for the blogs in the search area provided. Also on click on the tags should filter
the blogs records.
*/
const handleChange = (e) => {
setSearchTerm(e.target.value);
}
useEffect(() => {
const fetchData = async () => {
try {
const res = await axios.get('http://localhost:5000/service/blogpost');
setSearchResults(res.data.items);
} catch (e) {
console.log(e);
}
}
fetchData();
}, []);
useEffect(() => {
const results = searchResults.filter(blog =>
blog.fields.title.toLowerCase().includes(searchTerm) || blog.fields.title.toUpperCase().includes(searchTerm) || blog.fields.shortDescription.toLowerCase().includes(searchTerm)
|| blog.fields.shortDescription.toUpperCase().includes(searchTerm)
);
setSearchResults(results);
}, [searchTerm, searchResults]);
const getFilterTags = (event) => {
const tagText = event.target.innerText;
console.log("Print tag of a:"+tagText);
const results = searchResults.filter(blog =>
blog.fields.title.toLowerCase().includes(tagText) || blog.fields.title.toUpperCase().includes(tagText)
);
setSearchResults(results);
}
const renderPosts = () => {
if (isLoading) return(<div className="loadingIcon"> <p className="noSearchData">Loading...</p> </div>);
return (
<div className="wrap">
<div className="row">
<div className="column left" >
<h3>Search:</h3>
<label>
<div className="playerSearch_Home">
<div className="playerSearch_Icon">
<input type="text" className="playerSearch_Home_Input" placeholder="search posts..." value={searchTerm} onChange={handleChange} />
</div>
</div>
</label>
<h3>Tags:</h3>
<label>
{
searchResults.map(({ fields: { id, tags } }) => (
<div key={id} className="techtags">
{
Array.isArray(tags) ? (
tags.map((tag) => (
<a onClick={getFilterTags} className="grouptechtags" style={{backgroundColor: `${showColor}`},{ marginRight: "10px" }} key={tag}>{tag}</a>
))
) : (
<a onClick={getFilterTags} style={{backgroundColor: `${showColor}`}} className="grouptechtags">{tags}</a>
)
}
</div>
))
}
</label>
<div className="twitterlink">
Follow me on twitter
</div>
<div className="reactStunning">
🛠️ Built with react...!
</div>
<div>
<small className="copyright">© 2020 Soccerway</small>
</div>
</div>
<div className="column right" >
{!searchResults.length && (<div> <p className="noSearchData"><Wave text="No results available...!"/></p> </div>)}
<div className="container">
{
searchResults.map(({ sys: { id, createdAt}, fields: { title, image, shortDescription, description, tags, skillLevel, duration, slug } }) => (
<div key={id} className="column-center">
<article key={id} className="blogmaintile">
<div className="blogtitle">
<span key={title}>{title}</span>
</div>
<section>
<p className="blogdescription" key={shortDescription}>{shortDescription}</p>
<span className="blogcreateddate" key={createdAt}>{Moment(createdAt).format('MMM DD YYYY')}</span>
<span style={{display:"none"}} key={tags}>{tags}</span>
</section>
<section>
<p className="bloglongdescription" key={description}>{description}</p>
</section>
<section className="col1">
{
<span className="difftags" key={skillLevel} >{skillLevel}</span>
}
</section>
<span className="blogduration" key={duration} >{duration} min</span>
<section className="col2">
<a href={slug}>...more {'>'}{'>'}</a>
</section>
</article>
</div>
))
}
</div>
</div>
</div>
</div>
)
};
return (
<div className="posts__container">
<div className="posts">{renderPosts()}</div>
</div>
);
}
server.js
const express = require('express');
const bodyParser = require("body-parser");
const axios = require('axios');
const path = require('path');
const cors = require("cors");
const { get } = require('http');
const app = express()
const port = 5000
app.use(cors({
origin: "http://localhost:3000"
}));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.get('/service/blogpost', async(req, res) => {
try {
const blogposts = await axios({
url: 'https://cdn.contentful.com/spaces/some_space_id/entries?access_token=some_token&limit=1000&skip=0',
method:"GET"
});
res.status(200).send(blogposts.data);
} catch (e) {
res.status(500).json({ fail: e.message });
}
})
app.listen(port, () => {
console.log(`Listening at http://localhost:${port}`)
})
App.js
import React from 'react';
import { BrowserRouter, Route, Switch } from "react-router-dom";
import "./cssmodules/home.css";
import "./cssmodules/tutorialslist.css"
import "./cssmodules/singlepost.css";
import Home from "./components/Home";
import Tutorials from "./components/Tutorials";
import Navigation from './components/Navigation';
import TutorialsList from './components/TutorialsList';
import SinglePost from './components/SinglePost';
function App() {
return (
<BrowserRouter>
<Navigation/>
<Switch>
<Route exact path="/" component={Home} />
<Route path="/tutorials" component={Tutorials} />
<Route path="/tutorialslist" component={TutorialsList} />
<Route path="/:id" component={SinglePost} />
</Switch>
</BrowserRouter>
);
};
export default App;
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
import 'bootstrap/dist/css/bootstrap.css';
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById('root')
);
serviceWorker.unregister();
I think that your problem is there:
useEffect(() => {
const results = searchResults.filter(blog =>
blog.fields.title.toLowerCase().includes(searchTerm) || blog.fields.title.toUpperCase().includes(searchTerm) || blog.fields.shortDescription.toLowerCase().includes(searchTerm)
|| blog.fields.shortDescription.toUpperCase().includes(searchTerm)
);
setSearchResults(results);
}, [searchTerm, searchResults]);
Method filter returns a new array, you save it with setSearchResults(), React calls rerender, this useEffect detect a new searchResults, run its callback... and again and again.
Maybe you need in useMemo to calculate filtered results or calculate it in imminently after receiving from the server?
Up
Maybe something like this:
// Initiate a state for fetched posts.
const [posts, setPosts] = useState([]);
// Fetch data from server on mount.
useEffect(() => {
const fetchData = async () => {
try {
const { data: { items } } = await axios.get('http://localhost:5000/service/blogpost');
setPosts(items);
} catch (e) {
console.log(e);
}
}
fetchData();
}, []);
// Extract Tags from Posts with memoization.
const tags = useMemo(() => {
return posts.reduce((result, post) => {
const { fields: { tags } } = post;
const normalizedTags = Array.isArray(tags) ? tags : [tags];
return [
...result,
...normalizedTags,
];
}, []);
}, [posts]);
// Filter Posts with memoization.
const filteredPosts = useMemo(() => {
const term = searchTerm.toLowerCase();
return posts.filter((post) => {
const title = post.fields.title.toLowerCase();
const description = post.shortDescription.title.toLowerCase();
return [title, description].includes(term); // You can extend the condition with a check of selected tags here.
});
}, [posts, searchTerm]);
// Render `tags` and `filteredPosts` in your template.
Sorry if I don't understand your task