how to display people data in the body - javascript

Hi guys trying to make an mini application in react JS , in that application i want to display data in the my body part when i do search on my textbar , so anyone tell me how can i do it or what should i do to display data?
App.js This is my main component
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 data={people}/>
<Planet data={planet}/>
</div>
);
}
export default App;
Star.js
This is my star component where i fetch my all star war apis
import React, { useState, useEffect } from 'react';
import './Star.css';
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() {
let result = await fetch("https://swapi.dev/api/people/?format=json");
let data = await result.json();
setPeople(data.results);
}
async function fetchPlanet() {
let result = await fetch("https://swapi.dev/api/planets/?format=json");
let data = await result.json();
setPlanet(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>
</div>
</div>
)
}
export default Star;
people.js
This is my people that i want to display in the my body part
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.name}</h4>
</div>
</div>
</div>
)
})}
</div>
);
};
export default People;

If I understand correctly your issue, you want to display the People component and the issue is how to pass it the data fetched in the Star component.
The solution is to move the state of the data in the parent component so that it can be passed easily to all its children.
function App(props) {
const [people, setPeople] = useState([]);
const [planet, setPlanet] = useState([]);
useEffect(() => {
async function fetchPeople() {
let result = await fetch("https://swapi.dev/api/people/?format=json");
let data = await result.json();
setPeople(data.results);
}
async function fetchPlanet() {
let result = await fetch("https://swapi.dev/api/planets/?format=json");
let data = await result.json();
setPlanet(data.results);
}
fetchPeople();
fetchPlanet();
}, [])
return (
<div className="App">
<Star
people={people} //if you need these in the Star component
planet={planet} //if you need these in the Star component
/>
<People data={people}/>
<Planet data={planet}/>
</div>
);
}

Related

Material UI Pagination

I don't understand why my page can't recognize other pages when I click (for example on page 2, the same page appears again and again)
This is in MealNew.js component:
import React, {useEffect, useState } from "react";
import './MealNew.css';
import Card from "../UI/Card";
import AppPagination from "./AppPagination";
const MealNew = () => {
const [data, setData] = useState([]);
const [showData, setShowData] = useState(false);
const [query,setQuery] = useState('');
const[page,setPage] = useState(9);
const[numberOfPages,setNumberOfPages]= useState(10);
const handleClick = () => {
setShowData(true);
const link = `https://api.spoonacular.com/recipes/complexSearch?query=${query}&apiKey=991fbfc719c743a5896bebbd98dfe996&page=${page}`;
fetch (link)
.then ((response)=> response.json())
.then ((data) => {
setData(data.results)
setNumberOfPages(data.total_pages)
const elementFood = data?.map((meal,key) => {
return (<div key={key}>
<h1>{meal.title}</h1>
<img src={meal.image}
alt='e-meal'/>
</div> )
})
const handleSubmit = (e) => {
e.preventDefault();
handleClick();
}
useEffect(()=> {
handleClick();
},[page])
return (
<Card className="meal">
<form onSubmit={handleSubmit}>
<input
className="search"
placeholder="Search..."
value={query}
onChange={(e)=>setQuery(e.target.value)}/>
<input type='submit' value='Search'/>
</form>
<li className="meal">
<div className = 'meal-text'>
<h5>{showData && elementFood}</h5>
<AppPagination
setPage={setPage}
pageNumber={numberOfPages}
/>
</div>
</li>
</Card>
) }
export default MealNew;
This is in AppPagination.js component:
import React from "react";
import { Pagination } from "#mui/material";
const AppPagination = ({setPage,pageNumber}) => {
const handleChange = (page)=> {
setPage(page)
window.scroll(0,0)
console.log (page)
}
return (
<div >
<div >
<Pagination
onChange={(e)=>handleChange(e.target.textContent)}
variant="outlined"
count={pageNumber}/>
</div>
</div>
)
}
export default AppPagination;
Thanks in advance, I would appreciate it a lot
The only error I am getting in Console is this:
Line 64:3: React Hook useEffect has a missing dependency: 'handleClick'. Either include it or remove the dependency array react-hooks/exhaustive-deps
You are not following the spoonacular api.
Your link looks like this:
https://api.spoonacular.com/recipes/complexSearch?query=${query}&apiKey=<API_KEY>&page=${page}
I checked the spoonacular Search Recipes Api and there's no page parameter you can pass. You have to used number instead of page.
When you receive response from the api, it returns the following keys: offset, number, results and totalResults.
You are storing totalResults as totalNumberOfPages in state which is wrong. MUI Pagination count takes total number of pages not the total number of records. You can calculate the total number of pages by:
Math.ceil(totalRecords / recordsPerPage). Let say you want to display 10 records per page and you have total 105 records.
Total No. of Pages = Math.ceil(105/10)= 11
Also i pass page as prop to AppPagination component to make it as controlled component.
Follow the documentation:
Search Recipes
Pagination API
Complete Code
import { useEffect, useState } from "react";
import { Card, Pagination } from "#mui/material";
const RECORDS_PER_PAGE = 10;
const MealNew = () => {
const [data, setData] = useState([]);
const [showData, setShowData] = useState(false);
const [query, setQuery] = useState("");
const [page, setPage] = useState(1);
const [numberOfPages, setNumberOfPages] = useState();
const handleClick = () => {
setShowData(true);
const link = `https://api.spoonacular.com/recipes/complexSearch?query=${query}&apiKey=<API_KEY>&number=${page}`;
fetch(link)
.then((response) => response.json())
.then((data) => {
setData(data.results);
const totalPages = Math.ceil(data.totalResults / RECORDS_PER_PAGE);
setNumberOfPages(totalPages);
});
};
const elementFood = data?.map((meal, key) => {
return (
<div key={key}>
<h1>{meal.title}</h1>
<img src={meal.image} alt='e-meal' />
</div>
);
});
const handleSubmit = (e) => {
e.preventDefault();
handleClick();
};
useEffect(() => {
handleClick();
console.log("first");
}, [page]);
return (
<Card className='meal'>
<form onSubmit={handleSubmit}>
<input className='search' placeholder='Search...' value={query} onChange={(e) => setQuery(e.target.value)} />
<input type='submit' value='Search' />
</form>
<li className='meal'>
<div className='meal-text'>
<h5>{showData && elementFood}</h5>
<AppPagination setPage={setPage} pageNumber={numberOfPages} page={page} />
</div>
</li>
</Card>
);
};
const AppPagination = ({ setPage, pageNumber, page }) => {
const handleChange = (page) => {
setPage(page);
window.scroll(0, 0);
console.log(page);
};
console.log("numberOfPages", pageNumber);
return (
<div>
<div>
<Pagination
page={page}
onChange={(e) => handleChange(e.target.textContent)}
variant='outlined'
count={pageNumber}
/>
</div>
</div>
);
};
export default MealNew;

(React)Filter through api by search term

I'm trying to use a search bar component in my React project to search/filter through an api list of movies by title. Right now my search term is console logging, but i'm trying to filter the movie list to only show the titles that match the term. I'm having issues with updating my movies state with the term and displaying the new array.
App
import SearchBar from "../Search/SearchBar"
export default function Movies() {
const [movies, setMovies] = useState([]);
async function getMovies() {
const movieData = await fetchMovies();
console.log(movieData);
setMovies(
movieData.data.data.sort((a, b) => a.title.localeCompare(b.title))
);
}
useEffect(() => {
getMovies();
}, []);
async function onSearchSubmit(term) {
console.log(term)
let fill = []
movies.filter((movie) => {
if(movie.title === term) {
fill.push(movie.title)
}
setMovies(fill)
})
}
return (
<>
<Nav
movies={movies}
setMovies={setMovies}/>
<SearchBar
onSubmit={onSearchSubmit}/>
{movies ? (
<div>
<div>
{movies.map((m, idx) => {
return <div key={idx}>{m.title}</div>;
})}{" "}
</div>
</div>
) : (
"loading..."
)}
</>
);
}
Search Bar component
import React,{useState} from 'react';
const SearchBar = ({onSubmit}) => {
const [term, setTerm] = useState("")
function onFormSubmit(event){
event.preventDefault()
onSubmit(term)
}
return (
<div className="ui segment">
<form onSubmit={onFormSubmit} className="ui form">
<div className="field">
<label>Movie Search</label>
<input
type="text"
value={term}
onChange={(e) => setTerm( e.target.value)}
/>
</div>
</form>
</div>
);
}
export default SearchBar;
First of all additional state is needed to record the loaded moves list:
const movies = useRef([]);
const [filteredMovies, setFilteredMovies] = useState([]);
It is better to declare handlers with useCallback and avoid the mixture of declarative and imperative styles. For example:
const onSearchSubmit = useCallback(async (term) => {
if (term) {
const _ = movies.current.filter(({ title }) => (title === term));
setFilteredMovies(_);
} else {
setFilteredMovies(movies.current);
}
}, [movies]);
https://jsfiddle.net/pq9xkewz/2/

React not importing file. Console shows no errors

Trying to practice api but I'm stuck trying to import the recipe template. The form shows but nothing else. The console also shows no errors. Any help would be appreciated.
Here is the App.js
import React, { useEffect, useState } from "react";
import Recipe from "./Recipe.js";
function App() {
let [recipes, setRecipes] = useState([]);
useEffect(() => {
getRecipes();
}, []);
const getRecipes = async () => {
const response = await fetch(
`///url///`
);
const data = await response.json();
setRecipes = data.hits;
console.log(data.hits);
};
return (
<div className="App">
<form className="search-form">
<input type="text" className="search-bar" />
<button type="submit" className="search-button">
Search
</button>
</form>
{recipes.map(recipe => (
<Recipe />
))}
</div>
);
}
export default App;
Here is Recipe.js
const Recipe = () => {
return (
<div>
<h1>Title</h1>
<p>Calories</p>
</div>
);
};
export default Recipe;
You're not updating the recipes state inside the getRecipes function correctly. You should call the setRecipes state updater function with the new state.
setRecipes = data.hits;
should be
setRecipes(data.hits)

I am unable to fetch different values from API except for "chicken"

As the query will fetch the value that is provided in useState. But I want the search bar to search for recipes provided by me. Can anybody help me on how I can do that.
import React, { useEffect, useState } from 'react';
import Recipe from './Recipe';
import './App.css';
const App = ()=>{
const APP_ID= '2*****'
const APP_KEY= 'f******************'
const [recipes, setRecipes] = useState([]);
const [search, setSearch] = useState("");
const [query, setQuery] = useState('chicken');
useEffect(() =>{
const getRecipes = async()=>{
const response = await fetch(`https://api.edamam.com/search?q=${query}&app_id=${APP_ID}&app_key=${APP_KEY}`);
const data = await response.json();
setRecipes(data.hits)
};
getRecipes();
},[query]);
const updateSearch = e=>{
setSearch(e.target.value);
}
const getSearch = e =>{
setQuery(search);
setSearch('');
}
return(
<div className="App">
<form onSubmit={getSearch} className="search-form">
<input className="search-bar" type="text" value={search} onChange={updateSearch} />
<button className="search-button" type="submit">Search</button>
</form>
{recipes.map(recipe =>(
<Recipe
key={recipe.recipe.label}
title={recipe.recipe.label}
calories={recipe.recipe.calories}
image={recipe.recipe.image} />
))}
</div>
)
}
export default App;
don't create multiple states for the same thing.
pass search string to the fetch API
import React, { useState, useEffect } from "react";
import "./styles.css";
const App = () => {
const APP_ID = "2***********";
const APP_KEY = "f*********";
const [recipes, setRecipes] = useState([]);
const [search, setSearch] = useState("");
useEffect(() => {
try {
const getRecipes = async () => {
const response = await fetch(
`https://api.edamam.com/search?q=${search}&app_id=${APP_ID}&app_key=${APP_KEY}`
);
const data = await response.json();
setRecipes(data.hits);
};
getRecipes();
} catch (error) {
// handle error here
console.error(error);
}
}, [search]);
const updateSearch = (e) => {
setSearch(e.target.value);
};
const getSearch = (e) => {
setSearch("");
};
return (
<div className="App">
<form onSubmit={getSearch} className="search-form">
<input
className="search-bar"
type="text"
value={search}
onChange={updateSearch}
/>
<button className="search-button" type="submit">
Search
</button>
</form>
{recipes.map((recipe) => (
<Recipe
key={recipe.recipe.label}
title={recipe.recipe.label}
calories={recipe.recipe.calories}
image={recipe.recipe.image}
/>
))}
</div>
);
};
export default App;
edit:
If initially, you want to have chicken results from API, change the response variable to this:
const response = await fetch(
`https://api.edamam.com/search?q=${search || "chicken"}&app_id=${APP_ID}&app_key=${APP_KEY}`
);

Fetching the charities using the global giving API using react

I'm using global giving API to make a charity finder app.
I have two dropdowns and a search button in the CharityFinderPage.js component. Now on clicking the search button, I want to fetch the charities using the themeId. The endpoint is https://api.globalgiving.org/api/public/projectservice/themes/{themeId}/projects
I know that on handleClick I should fetch the charities, but how do I get the value of themeId in the handleClick of CharityFinderPage.js component.
What I want is to show a new card component when the button clicks like showing a charity card with the fields populated on it from the data of the API, but first I need to be able to get the data from the API, then I can render a new component.
Here's the code:
CharityFinderPage.js
const CharityFinderPage = () => {
const handleClick = () => {
console.log("inside handleclick")
}
return (
<div style={containerStyle}>
<h1>Charity Finder ❤️</h1>
<h3>Search for charity</h3>
<h4>
Filter charities by personal search conditions. Use the dropdown below
to see charities matching your criteria.
</h4>
<Themes />
<Regions />
<button onClick={handleClick}>Search</button>
</div>
)
}
export default CharityFinderPage
Themes.js
import React, { useEffect, useState } from "react"
import axios from "axios"
const url = `https://api.globalgiving.org/api/public/projectservice/themes.json?api_key=${process.env.REACT_APP_api_key}`
const Themes = () => {
const [isLoading, setIsLoading] = useState(false)
const [selectValue, setSelectValue] = useState("")
const [themes, setThemes] = useState([])
useEffect(() => {
const fetchThemes = async () => {
try {
setIsLoading(true)
const result = await axios.get(url)
setThemes(result.data.themes.theme)
setIsLoading(false)
} catch (err) {
console.log(err)
}
}
fetchThemes()
}, [])
const handleChange = (event) => {
console.log("inside handleChange", event.target.value)
setSelectValue(event.target.value)
}
return (
<div>
{isLoading ? (
<h4>Loading......</h4>
) : (
<div>
<label>Select theme: </label>
<select onChange={handleChange} value={selectValue}>
{themes.map((theme, id) => {
return <option key={id}>{theme.name}</option> //{id} is the `themeId`
})}
</select>
</div>
)}
</div>
)
}
export default Themes
Regions component is exactly similar to Themes.
So the thing that you need to do here is called lifting the state up.
You need to move your states of theme component to CharityFinder component
I am lifting only selectedValue because that is all that you need
CharityFinderPage.js
const CharityFinderPage = () => {
const [selectValue, setSelectValue] = useState("")
const handleClick = () => {
console.log(`inside handleclick with ${selectValue}`)
}
return (
<div style={containerStyle}>
<h1>Charity Finder ❤️</h1>
<h3>Search for charity</h3>
<h4>
Filter charities by personal search conditions. Use the dropdown below
to see charities matching your criteria.
</h4>
// you can pass the setSelectValue as prop to Themes component
<Themes setSelectValue={setSelectValue} selectValue={selectValue} />
<Regions />
<button onClick={handleClick}>Search</button>
</div>
)
}
export default CharityFinderPage
Theme.js
import React, { useEffect, useState } from "react"
import axios from "axios"
const url = `https://api.globalgiving.org/api/public/projectservice/themes.json?api_key=${process.env.REACT_APP_api_key}`
const Themes = ({ selectValue, setSelectValue }) => {
const [isLoading, setIsLoading] = useState(false)
const [themes, setThemes] = useState([])
useEffect(() => {
const fetchThemes = async () => {
try {
setIsLoading(true)
const result = await axios.get(url)
setThemes(result.data.themes.theme)
setIsLoading(false)
} catch (err) {
console.log(err)
}
}
fetchThemes()
}, [])
const handleChange = (event) => {
console.log("inside handleChange", event.target.value)
setSelectValue(event.target.value)
}
return (
<div>
{isLoading ? (
<h4>Loading......</h4>
) : (
<div>
<label>Select theme: </label>
<select onChange={handleChange} value={selectValue}>
{themes.map((theme, id) => {
return <option key={id}>{theme.name}</option> //{id} is the `themeId`
})}
</select>
</div>
)}
</div>
)
}
export default Themes
You can do this.
const CharityFinderPage = () => {
const [themeId, setThemeId] = useState();
const handleClick = () => {
console.log("inside handleclick")
// make call to endpoint with themeId
}
return (
<div style={containerStyle}>
<h1>Charity Finder ❤️</h1>
<h3>Search for charity</h3>
<h4>
Filter charities by personal search conditions. Use the dropdown below
to see charities matching your criteria.
</h4>
<Themes setThemeId={setThemeId} />
<Regions />
<button onClick={handleClick}>Search</button>
</div>
)
}
export default CharityFinderPage
Then in Themes.js:
...
const handleChange = (event) => {
console.log("inside handleChange", event.target.value)
props.setThemeId(event.target.value);
setSelectValue(event.target.value)
}
...

Categories