I have a movie app which displays a card for each movie in a state.
I would like to use a dynamic search bar to render movies corresponding to the search input value.
For instance, if I start to write "Har", I want to see only movies with a title that begins with "Har".
The app code :
import React, { useState, useEffect } from "react";
import "./App.css";
import Logo from "../components/Logo";
import Search from "../components/Search";
import Add_movie_button from "../components/Add_movie_button";
import Random_movie_button from "../components/Random_movie_button";
import Movie_card from "../components/Movie_card";
import axios from "axios";
const BASE_URL = "https://api.themoviedb.org/3/movie/";
const API_KEY = "4bcd155b9b8734cb8559319cdbfaf62f";
function App() {
const [movieinfos, setMovieinfos] = useState([]);
console.log(movieinfos);
useEffect(() => {
axios
.get("http://localhost:5000")
.then(function (response) {
const movies = response.data.movies;
console.log(response.data.movies);
return Promise.all(
movies.map((movie) =>
axios.get(
`${BASE_URL}${movie.movieid}?api_key=${API_KEY}&language=fr`
)
)
);
})
.then((responses) => {
console.log(responses);
setMovieinfos(
responses.map((response) => ({
Genres: response.data.genres,
Overview: response.data.overview,
Poster: response.data.poster_path,
Company: response.data.production_companies,
Release: response.data.release_date,
Title: response.data.title,
Id: response.data.id,
}))
);
});
}, []);
return (
<div className="App">
<div className="Header">
<Logo />
</div>
<div className="Menu">
<Search movieinfos={movieinfos} setMovieinfos={setMovieinfos} />
<Add_movie_button />
<Random_movie_button data={movieinfos} />
</div>
<div className="Movies">
{movieinfos.map((movie) => (
<Movie_card key={movie.Title} data={movie} />
))}
</div>
</div>
);
}
export default App;
The search bar code :
import React from "react";
import "./style.css";
const Search = (props) => {
console.log(props);
return (
<div className="Search">
<input
type="search"
id="Search_input"
placeholder="Rechercher un film ..."
value= //WHAT DO I NEED TO WRITE HERE ?
onChange={(event) =>
/*WHAT DO I NEED TO WRITE HERE ?*/ event.target.value
}
/>
</div>
);
};
export default Search;
You could create a state variable
[searchWord, setSearchWord] = useState('')
your input would then contain
value={searchWord}
onChange={e => setSearchWord(e.target.value)}
You could then filter your array movieinfos with the searchWord and map the returning array to display only the movies with the search world
movieinfos.filter(movie => movie.title.includes(searchWord)).map(movie => return <Movie_card key={movie.Title} data={movie} />)
Related
By using console.log(responseData.places) I have checked the fetching works since I am using a hook for this and seems to work fine until I setLoadedPlaces with is the method I use to update the loadedPlaces which I later use to get the values to fill the frontend part of the website.
This is the output I get from this console.log I did and the values are correct.
[{…}]
0: address: "sis se puede
busrespect: 'tu puedes',
creator: "6384e2f543f63be1c560effa"
description: "al mundial"
id: "6384e30243f63be1c560f000"
image:"https://upload.wikimedia.org/wikipedia/commons/thumb/1/10/Empire_State_Building_%28aerial_view%29.jpg/400px-Empire_State_Building_%28aerial_view%29.jpg"location: {lat: -12.086158, lng: -76.898019}
title: "Peru"
__v: 0
_id: "6384e30243f63be1c560f000"[[Prototype]]:
Objectlength: 1[[Prototype]]: Array(0)
So after this this the code I have in the frontend (SINCE the backend works properly) Let me know if you have any doubts with this logic
This is UserPlaces.js
import React, {useState, useEffect } from 'react';
import PlaceList from '../components/PlaceList';
import { useParams } from 'react-router-dom';
import { useHttpClient } from '../../shared/hooks/http-hook';
import ErrorModal from '../../shared/components/UIElements/ErrorModal';
import LoadingSpinner from '../../shared/components/UIElements/LoadingSpinner';
const UserPlaces = () => {
const {loadedPlaces, setLoadedPlaces} = useState();
const {isLoading, error, sendRequest, clearError } = useHttpClient();
const userId = useParams().userId;
useEffect(() => {
const fetchPlaces = async () => {
try {
const responseData = await sendRequest(
`http://localhost:5000/api/places/user/${userId}`
);
console.log(responseData.bus_stops)
setLoadedPlaces(responseData.bus_stops);
} catch (err) {}
};
fetchPlaces();
}, [sendRequest, userId]);
return (
<React.Fragment>
<ErrorModal error={error} onClear={clearError} />
{isLoading && (
<div className="center">
<LoadingSpinner />
</div>
)}
{!isLoading && loadedPlaces && <PlaceList items={loadedPlaces} />}
</React.Fragment>
);
};
export default UserPlaces;
This is Place-List.js
import React from 'react';
import "./PlaceList.css"
import Card from '../../shared/components/UIElements/Card'
import PlaceItem from './PlaceItem';
import Button from '../../shared/components/FormElements/Button';
const PlaceList = props => {
if (props.items.length === 0) {
return (
<div className='place-list-center'>
<Card>
<h2>No bus stops available. Be the first one to create one!</h2>
<Button to='/places/new'> Create Bus Stop </Button>
</Card>
</div>
);
}
return (
<ul className="place-list">
{props.items.map(bus_stops => (
<PlaceItem
key={bus_stops.id}
id={bus_stops.id}
image={bus_stops.image}
title={bus_stops.title}
busrespect={bus_stops.busrespect}
description={bus_stops.description}
address={bus_stops.address}
creatorId={bus_stops.creator}
coordinates={bus_stops.location}
/>
))}
</ul>
);
};
export default PlaceList;
This is PlaceItem.js
import React, { useState } from 'react';
import { useContext } from 'react';
import Card from '../../shared/components/UIElements/Card';
import Button from '../../shared/components/FormElements/Button';
import Modal from '../../shared/components/UIElements/Modal';
import Map from '../../shared/components/UIElements/Map';
import {AuthContext} from '../../shared//context/auth-context'
import "./PlaceItem.css";
const PlaceItem = props => {
const auth = useContext(AuthContext);
const [showMap, setShowMap] = useState(false);
const [showConfirmModal, setShowConfirmModal] = useState(false);
const openMapHandler = () => setShowMap(true);
const closeMapHandler = () => setShowMap(false);
const showDeleteWarningHandler = () => {
setShowConfirmModal(true);
};
const cancelDeleteHandler = () => {
setShowConfirmModal(false);
};
const confirmDeleteHandler = () => {
setShowConfirmModal(false); //when clicked close the new Modal
console.log('DELETING...');
};
return (
<React.Fragment>
<Modal show={showMap}
onCancel={closeMapHandler}
header={props.address}
contentClass="place-item__modal-content"
footerClass="place-item__modal-actions"
footer={<Button onClick={closeMapHandler}>Close </Button>}
>
<div className='map-container'>
<Map center={props.coordinates} zoom={16}/> {/* Should be props.coordinates but we writing default data for now until geocoding solved. */}
</div>
</Modal>
<Modal
show={showConfirmModal}
onCancel={cancelDeleteHandler}
header="Are you entirely sure?"
footerClass="place-item__modal-actions"
footer={
<React.Fragment>
<Button inverse onClick={cancelDeleteHandler}>
CANCEL
</Button>
<Button danger onClick={confirmDeleteHandler}>
DELETE
</Button>
</React.Fragment>
}
>
<p>
Do you want to proceed and delete this place? Please note that it
can't be undone thereafter.
</p>
</Modal>
<li className='"place=item'>
<Card className="place-item__content">
<div className='place-item__image'>
<img src={props.image} alt={props.title}/>
</div>
<div className='place-item__info'>
<h2>{props.title}</h2>
<h3>{props.address}</h3>
<p>{props.description}</p>
<p>{props.busrespect}</p>
</div>
<div className='place-item__actions'>
<Button inverse onClick={openMapHandler}> VIEW ON MAP</Button>
{auth.isLoggedIn && (<Button to={`/places/${props.id}`}> EDIT</Button> )}
{auth.isLoggedIn &&<Button danger onClick={showDeleteWarningHandler}> DELETE </Button>}
</div>
</Card>
</li>
</React.Fragment>
);
};
export default PlaceItem;
This is auth-context:
import { createContext } from "react";
export const AuthContext = createContext({
isLoggedIn: false,
userId: null,
login: () => {},
logout: () => {}});
This is is Modal.js
import React from 'react';
import ReactDOM from 'react-dom';
import Backdrop from './Backdrop';
import { CSSTransition } from 'react-transition-group';
import './Modal.css';
const ModalOverlay = props => {
const content =(
<div className={`modal ${props.className}`} style = {props.style}>
<header className={`modal__header ${props.headerClass}`}>
<h2>{props.header}</h2>
</header>
<form
onSubmit={
props.onSubmit ? props.onSubmit : event => event.preventDefault()
}
>
<div className={`modal__content ${props.contentClass}`}>
{props.children}
</div>
<footer className={`modal__content ${props.footerClass}`}>
{props.footer}
</footer>
</form>
</div>
);
return ReactDOM.createPortal(content, document.getElementById('modal-hook'));
};
const Modal = props => {
return (
<React.Fragment>
{props.show && <Backdrop onClick={props.onCancel} />}
<CSSTransition in={props.show}
mountOnEnter
unmountOnExit
timeout={200}
classNames="modal"
>
<ModalOverlay {...props}/>
</CSSTransition>
</React.Fragment>
);
};
export default Modal;
Also Trust the routing is correct since I have checked it already and I am just wondering if the logic in REACT with loadedPlaces, PlaceItema and PlaceList makes sense and it working. Let me know please. It will be really helpful.
Summary: Not getting any error but no visual data appears in the scren just the header of my website and the background (rest is empty) even though logic is functional.
const {loadedPlaces, setLoadedPlaces} = useState();
change the above line to
const [loadedPlaces, setLoadedPlaces] = useState();
hello im using rick & morty API, im trying to filter by location id i can search by id but if i clear the input and press enter the page loops and never render my data
im using a custom hook to call the API from inputs.
import axios from 'axios'
import React, { useEffect, useState } from 'react'
const useFetch = (URL) => {
const [response, setResponse] = useState()
useEffect(() => {
axios.get(URL)
.then(res => setResponse(res.data))
.catch(err => console.log(err))
}, [URL])
return response
}
export default useFetch
here im rendering the characters from rick and morty
import React from 'react'
import useFetch from '../hooks/useFetch'
const CardResidents = ({url}) => {
const residents = useFetch(url)
const bgColor = {
}
if (residents?.status === "Dead") {
bgColor.backgroundColor = "red"
}else if (residents?.status === "Alive") {
bgColor.backgroundColor = "green"
}else {
bgColor.backgroundColor = "gray"
}
return (
<div className='resident'>
<div className='status'><div className='circle' style={bgColor}></div> {residents?.status}</div>
<img className='resident-img' src={residents?.image} alt="" />
<h2 className='resident-name'>{residents?.name }</h2>
<hr />
<p className='resident-info'>Type</p>
<p className='resident-fetch'>{residents?.type }</p>
<p className='resident-info'>Origin</p>
<p className='resident-fetch'>{residents?.origin.name }</p>
<p className='resident-info'>Appearance in episodes</p>
<p className='resident-fetch'>{residents?.episode.length}</p>
</div>
)
}
export default CardResidents
this is the input im using to search location by id, but everytime y clear my input the page starts an infinity loop
import React from 'react'
const Query = ({setQueryFetch}) => {
const submitQuery = (e) => {
e.preventDefault()
const test = e.target.query.value
setQueryFetch(test)
console.log( test + "query")
}
return (
<form action="" onSubmit={submitQuery}>
<input id='query' type="text" placeholder='Search for locations between 1 - 126'/>
</form>
)
}
export default Query
and this is my main component where im renderin everything, im trying to select if the data will render by the randomID, or my query
import { useState } from 'react'
import './App.css'
import CardResidents from './components/CardResidents'
import LocationInfo from './components/LocationInfo'
import useFetch from './hooks/useFetch'
import banner from '../public/rick-morty-banner.jpg'
import Query from './components/Query'
function App() {
const randomId = Math.ceil(Math.random() * (126 - 1) +1)
const [queryFetch, setQueryFetch] = useState("")
let location = useFetch(`https://rickandmortyapi.com/api/location/${randomId}`)
if (queryFetch != "") {
console.log(queryFetch + " app")
location = useFetch(`https://rickandmortyapi.com/api/location/${queryFetch}`)
}else {
location = useFetch(`https://rickandmortyapi.com/api/location/${randomId}`)
}
return (
<div className="App">
<img className='banner' src={banner} alt="" />
<Query setQueryFetch={setQueryFetch}/>
<LocationInfo location={location}/>
<div className='resident-container'>
{
location?.residents.map(url =>(
<CardResidents
key={url}
url={url}
/>
))
}
</div>
</div>
)
}
export default App
I want to share Child Component (Product.js) data into Parent Component (App.js) without button click. I will use useState with context API. I don't know how to passed this data without click event.
Product.js data display into console.log() into App.js component.
App.js
import React from 'react';
import Product from './Product';
function App() {
return (
<div className="App">
<Product />
</div>
);
}
export default App;
Product.js
import React from 'react';
const Product = () => {
return (
<div>
Product Name: <input type="text" />
<br />
Description:- <input type="text" />
</div>
)
}
export default Product
Please help I have no advance knowledge of react.
There are three ways to share information without click event with useContext and useState.
useContext
useState in childComponent
useState in parentComponent
1. useContext
import { createContext, useContext, useState } from 'react';
import React from 'react';
const Context = createContext();
const Product = () => {
const [info, setInfo] = useContext(Context);
return (
<div>
Product Name: <input type="text" value={info.name} onChange={(e) => {
setInfo({ ...info, name: e.target.value });
}} />
<br />
Description:- <input type="text" value={info.desc} onChange={(e) => {
setInfo({ ...info, desc: e.target.value });
}} />
</div>
);
}
function App() {
const [info, setInfo] = useState({
name: '',
desc: ''
});
return (
<div className="App">
<Context.Provider value={[info, setInfo]}>
<Product />
</Context.Provider>
</div>
);
}
export default App;
If you have each component in a file. You have to create the context in a third file and import it from the parent and child component.
2. useState in childComponent
import { useEffect, useState } from 'react';
import React from 'react';
const Product = ({ setParentInfo }) => {
const [info, setInfo] = useState({ name: '', desc: '' });
useEffect(() => {
setParentInfo(info);
}, [info])
return (
<div>
Product Name: <input type="text" value={info.name} onChange={(e) => setInfo({ ...info, name: e.target.value })} />
<br />
Description:- <input type="text" value={info.desc} onChange={(e) => setInfo({ ...info, desc: e.target.value })} />
</div>
)
}
let info = { name: '', desc: '' }
function App() {
return (
<div className="App">
<Product setParentInfo={(newInfo) => {
info = { ...newInfo };
}} />
</div>
);
}
export default App;
3. useState in parentComponent
import { useState } from 'react';
import React from 'react';
const Product = ({ info, setParentInfo }) => {
return (
<div>
Product Name: <input type="text" value={info.name} onChange={(e) => setParentInfo({ ...info, name: e.target.value })} />
<br />
Description:- <input type="text" value={info.desc} onChange={(e) => setParentInfo({ ...info, desc: e.target.value })} />
</div>
)
}
function App() {
const [info, setInfo] = useState({ name: '', desc: '' });
console.log("parent: ", info);
return (
<div className="App">
<Product info={info} setParentInfo={(newInfo) => {
setInfo({ ...newInfo });
}} />
</div>
);
}
export default App;
I hope I've helped you. Have a nice day!
If its a direct child to parent communication, it's better to done this using props. Less code, works fine!
App.js:-
import React from 'react';
import Product from './Product';
function App() {
return (
<div className="App">
<Product
onProductNameChange={productName => console.log(productName)}
onProductDescChange={productDesc => console.log(productDesc)}
/>
</div>
);
}
export default App;
Product.js:-
import React from 'react';
const Product = ({onProductNameChange, onProductDescChange}) => {
return (
<div>
Product Name: <input type="text" onChange={e => onProductNameChange(e.target.value)} />
<br />
Description:- <input type="text" onChange={e => onProductDescChange(e.target.value)} />
</div>
)
}
export default Product
Share information without click event with useContext and useState.
App.js
import React from 'react';
import Store from './Store';
import ProductList from './ProductList';
function App() {
return (
<div className="App">
<Store>
<ProductList />
</Store>
</div>
);
}
export default App;
ProductList.js
import React, { useContext } from 'react';
import { Context } from './Store';
import Product from './Product';
import AddProduct from './AddProduct';
const ProductList = () => {
const [state, setState] = useContext(Context);
console.log(state);
return (
<>
<AddProduct />
<Product />
</>
)
}
export default ProductList
AddProduct.js
import React, { useContext} from 'react';
import { Context} from './Store';
const AddProduct = () => {
const [products, setProducts] = useContext(Context);
return (
<div>
Description:- <input type="text"
onChange={(e) => setProducts({ ...products, Description: e.target.value })}/>
</div>
)
}
export default AddProduct
Product.js
import React, { useContext} from 'react';
import { Context} from './Store';
const Product = () => {
const [products, setProducts] = useContext(Context);
return (
<>
<h2>Product</h2>
<p>Description: {products.Description}</p>
</>
)
}
export default Product
Store.js
import React, { useState } from 'react';
const product = {
Description: '',
};
export const Context = React.createContext();
const Store = ({ children}) => {
const [products, setProducts] = useState(product);
return (
<Context.Provider value={[products, setProducts]}>{children}</Context.Provider>
);
};
export default Store;
I have json data file. I want to make a search with the names of the data and display the typed names when I click the search button.
I get the value of input in the console when I type something however I am not able to display it on the screen
How can I display the value of this input ?
my code is below
PostResults.jsx
import React from "react";
const PostResults = (props) => {
const {name} = props.posts
return(
<div className="">
<p className="titles">{name}</p>
</div>
)
}
export default PostResults
Posts.jsx
import React, { useState, useEffect } from "react";
import PostResults from './PostResults'
const Posts = (props) => {
const [posts, setPosts] = useState([]);
const [searchTerm,setSearchTerm]=useState([]);
const getData = () => {
fetch('data.json')
.then(response => {
return response.json()
//console.log(response)
})
.then(data => {
setPosts(data)
console.log(data)
})
}
useEffect(() => {
getData()
},[])
const submitHandler = (event) => {
event.preventDefault()
{searchTerm ? searchTerm : console.log("none")}
}
return(
<div className="">
<input
type="text"
placeholder="Search Anything"
name="query"
onChange={e => setSearchTerm(e.target.value)}
className="search-input"
/>
<button
onClick={submitHandler}
type="submit"
className="search-button"
>
<i className="fas fa-search"></i>
</button>
{posts.map(posts => (
<PostResults key={posts.id} posts={posts}/>
))}
</div>
)
}
export default Posts
App.jsx
import React from "react";
import "./style.css";
import 'bootstrap/dist/css/bootstrap.min.css'
import Posts from './components/Posts'
export default function App() {
return (
<div className="container">
<div className="row">
< Posts />
</div>
</div>
);
}
I have a search function for which I'm attempting to raise the state into a parent component.
However, on attempting to submit the form I am presented with the error TypeError: Right side of assignment cannot be destructured and in reference to the line const {searchValues, setSearchValues} = useContext(SearchContext); in Search.js. I've been basing this code on this YouTube tutorial and can't seem to replicate the functionality when I have multiple values to pass and set.
SearchContext.js
import { createContext} from 'react'
export const SearchContext = createContext(null);
Body.js
Some code removed for readability.
import React, {useState} from "react";
import WikiHeader from './wikiheader/WikiHeader'
import WikiReference from './wikireference/WikiReference'
import Search from './search/Search'
import GoogleAd from './googlead/GoogleAd'
import {SearchContext} from "../contexts/SearchContext"
import {SummaryContext} from "../contexts/SummaryContext"
import {ReferenceContext} from "../contexts/ReferenceContext"
function Body() {
const [searchValues, setSearchValues] = useState({
searchCriteria: "",
resultId: ""
});
return (
<>
<SearchContext.Provider values={searchValues} onChange={setSearchValues}>
<Search />
</SearchContext.Provider>
</>
);
export default Body;
Search.js
import React, {useContext, Component} from "react";
import {SearchContext} from "../../contexts/SearchContext"
import "../../App.css"
function handleSubmit(event) {
event.preventDefault();
//fetch('http://127.0.0.1:5002/events/search/'+this.state.searchCriteria)
fetch('https://gist.githubusercontent.com/TheMightyLlama/e0ab261b30b7c957930b8eac29813180/raw/f39ea1323762b9dd796db7370a73f1a727e12566/gistfile2.txt')
.then(res => res.json())
.then((resultsData) => {
this.setState({
resultId: resultsData
})
console.log(resultsData);
})
.catch(console.log)
};
export function Search (){
const {searchValues, setSearchValues} = useContext(SearchContext);
return (
<div className="search container center">
<div className="input-group input-group-sm mb-3 center">
<div className="input-group-prepend">
<span className="input-group-text" id="inputGroup-sizing-sm">Wikipedia URL:</span>
</div>
<form onSubmit={(event) => {setSearchValues({searchCritera:event.target.value, resultId:1})}} center>
<input
type="text"
className="form-control center"
aria-label="Sizing example input"
aria-describedby="inputGroup-sizing-sm"
value={searchValues.searchCriteria}
onChange={event => {searchValues.searchCriteria = event.target.value} }
onFocus={() => {setSearchValues({searchCritera:'', resultId:''})}}
placeholder="Add a Url" />
</form>
</div>
</div>
);
}
export default Search;
You should provide the value you want to retrieve from useContext(SearchContext) to the property value of SearchContext.Provider.
So, in Body.js:
…
const searchState = useState({
searchCriteria: "",
resultId: ""
});
return (
<>
<SearchContext.Provider value={searchState}>
<Search />
</SearchContext.Provider>
</>
);
…
and in Search.js:
…
const [searchValues, setSearchValues] = useContext(SearchContext);
…