Reputation: 1183
I am rebuilding a static website in react https://movie-list-website-wt.netlify.app/ I am trying to transfer the search function to react. My current search function works as intended, it returns an array of movies that is being searched, I want it to update the data fetched by the movie cards so that when I search a query, the movie cards use the returned search data instead of the original one this is my App.js file
import React, { useEffect, useState } from 'react';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import Movies from './components/Movies';
import Topnav from './components/Topnav';
import './App.css';
import './components/Movies.css';
export const API_KEY = 'api_key=247b6aa143f3f2c0b100c0cbdfb1ac99';
export const BASE_URL = 'https://api.themoviedb.org/3';
export const API_URL = BASE_URL + '/discover/movie?sort_by=popularity.desc&' + API_KEY;
export const IMG_URL = 'https://image.tmdb.org/t/p/w500';
export const searchURL = BASE_URL + '/search/movie?'+ API_KEY;
function App() {
const [movies, setMovies] = useState ([]);
useEffect(() => {
fetch (API_URL)
.then(res => res.json())
.then(data => {
console.log(data);
setMovies(data.results);
});
}, [])
return (
<>
<Router>
<Topnav />
<div className="movie-container">
{movies.length > 0 &&
movies.map((movie) => (
<Movies key={movie.id} {...movie} />))}
</div>
<Routes>
<Route exact path='/' />
</Routes>
</Router>
</>
);
}
export default App;
and this is part of my Top navigation component that includes the search bar and function
import React, { useState } from 'react';
import { Link } from 'react-router-dom';
import './Topnav.css';
import { searchURL } from '../App';
function Topnav() {
const [click, setClick] = useState(false)
const handleClick = () => setClick(!click)
const modeToggle = () => {
document.body.classList.toggle('dark')
}
const [query, setQuery] = useState("")
const onChange = (e) => {
e.preventDefault();
setQuery(e.target.value)
fetch(searchURL+`&language=en-US&page=1&include_adult=false&query=${e.target.value}`)
.then((res) => res.json())
.then((data) => {
console.log(data.results);
})
}
return (
<>
<nav className="topnav">
<div className="topnav-container">
<Link to='/' className='topnav-logo'>
<img src={require('../img/logo.png').default} alt="logo" />
</Link>
<div className="wrapper">
<form id='search-bar'>
<input
type="text"
placeholder="Search"
className="search"
id="search"
value={query}
onChange={onChange}
/>
</form>
<label className="switch">
<input type="checkbox" id="mode-toggle" onChange={modeToggle}/>
</label>
</div>
Upvotes: 1
Views: 319
Reputation: 136
It is strait forward just move the method onChange to the parent component and pass it as a props
import React, { useEffect, useState } from 'react';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import Movies from './components/Movies';
import Topnav from './components/Topnav';
import './App.css';
import './components/Movies.css';
export const API_KEY = 'api_key=247b6aa143f3f2c0b100c0cbdfb1ac99';
export const BASE_URL = 'https://api.themoviedb.org/3';
export const API_URL = BASE_URL + '/discover/movie?sort_by=popularity.desc&' + API_KEY;
export const IMG_URL = 'https://image.tmdb.org/t/p/w500';
export const searchURL = BASE_URL + '/search/movie?'+ API_KEY;
function App() {
const [movies, setMovies] = useState ([]);
const [, setQuery] = useState("")
useEffect(() => {
fetch (API_URL)
.then(res => res.json())
.then(data => {
console.log(data);
setMovies(data.results);
});
}, [])
const onChange = (e) => {
e.preventDefault();
setQuery(e.target.value)
fetch(searchURL+`&language=en-US&page=1&include_adult=false&query=${e.target.value}`)
.then((res) => res.json())
.then((data) => {
console.log(data.results);
// DO what ever you want with the move array
})
}
return (
<>
<Router>
<Topnav onChange={onChange} query={query}/>
<div className="movie-container">
{movies.length > 0 &&
movies.map((movie) => (
<Movies key={movie.id} {...movie} />))}
</div>
<Routes>
<Route exact path='/' />
</Routes>
</Router>
</>
);
}
in this was way can edit the movie array in the APP Componenet then your child component will be something like
import React, { useState } from 'react';
import { Link } from 'react-router-dom';
import './Topnav.css';
import { searchURL } from '../App';
function Topnav({onChange, query}) {
const [click, setClick] = useState(false)
const handleClick = () => setClick(!click)
const modeToggle = () => {
document.body.classList.toggle('dark')
}
return (
<>
<nav className="topnav">
<div className="topnav-container">
<Link to='/' className='topnav-logo'>
<img src={require('../img/logo.png').default} alt="logo" />
</Link>
<div className="wrapper">
<form id='search-bar'>
<input
type="text"
placeholder="Search"
className="search"
id="search"
value={query}
onChange={onChange}
/>
</form>
<label className="switch">
<input type="checkbox" id="mode-toggle" onChange={modeToggle}/>
</label>
</div>
...
Upvotes: 0
Reputation: 13289
If you need to filter the movies
array in the Topnav
component you can just pass the setMovies
state function as prop to the component.
All you need to do is update the data in the onChange
method:
App.js
return (
<>
<Router>
<!-- Pass the prop to the component -->
<Topnav setMovies={setMovies}/>
<div className="movie-container">
{movies.length > 0 &&
movies.map((movie) => (
<Movies key={movie.id} {...movie} />))}
</div>
<Routes>
<Route exact path='/' />
</Routes>
</Router>
</>
);
Topnav.js
function Topnav({ setMovies }) {
...
const onChange = (e) => {
e.preventDefault();
setQuery(e.target.value)
fetch(searchURL+`&language=en-US&page=1&include_adult=false&query=${e.target.value}`)
.then((res) => res.json())
.then((data) => {
console.log(data.results);
// Update the data once fetched
setMovies(data.results)
})
}
...
Upvotes: 2