From 08731e0b98eeed79e4917406ab0d6b73b0c05967 Mon Sep 17 00:00:00 2001 From: Mitchell Date: Sun, 3 Nov 2024 00:20:56 +0200 Subject: [PATCH 1/4] Add constants --- src/App.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/App.js b/src/App.js index 75355bb..37eff79 100644 --- a/src/App.js +++ b/src/App.js @@ -6,6 +6,17 @@ import Landing from './components/Landing'; import Header from './components/Header'; import NoResults from './components/NoResults'; +// Constants +const CONFETTI_DURATION = 4000; +const YOUTUBE_OPTS = { + height: 500, + width: '100%', + playerVars: { + autoplay: 1, + controls: 0, + }, +}; + function App() { const [searchTerm, setSearchTerm] = React.useState(''); const [filteredMovies, setFilteredMovies] = React.useState(movies); From e68a237a8de9414e66041643333c02784a1d44de Mon Sep 17 00:00:00 2001 From: Mitchell Date: Sun, 3 Nov 2024 00:26:03 +0200 Subject: [PATCH 2/4] Destructure state for easy access --- src/App.js | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/src/App.js b/src/App.js index 37eff79..a29003b 100644 --- a/src/App.js +++ b/src/App.js @@ -18,16 +18,30 @@ const YOUTUBE_OPTS = { }; function App() { - const [searchTerm, setSearchTerm] = React.useState(''); - const [filteredMovies, setFilteredMovies] = React.useState(movies); - const [selectedMovie, setSelectedMovie] = React.useState({}); - const [noResults, setNoResults] = React.useState(false); - const [playTrailer, setPlayTrailer] = React.useState(false); - const [showLanding, setShowLanding] = React.useState(true); - const [showConfetti, setShowConfetti] = React.useState(false); + + const [appState, setAppState] = React.useState({ + searchTerm: '', + filteredMovies: movies, + selectedMovie: movies[0] || {}, + noResults: false, + playTrailer: false, + showLanding: true, + showConfetti: false, + }); + const playTrailerButtonRef = React.useRef(null); + const { + searchTerm, + filteredMovies, + selectedMovie, + noResults, + playTrailer, + showLanding, + showConfetti, + } = appState; + const handleGetStarted = () => { setShowConfetti(true); setTimeout(() => { From 37a5ada959d0011e123c32cc27047665c66ab81f Mon Sep 17 00:00:00 2001 From: Mitchell Date: Sun, 3 Nov 2024 00:33:26 +0200 Subject: [PATCH 3/4] Add memoized functions --- src/App.js | 48 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/src/App.js b/src/App.js index a29003b..708dcb5 100644 --- a/src/App.js +++ b/src/App.js @@ -42,31 +42,49 @@ function App() { showConfetti, } = appState; - const handleGetStarted = () => { - setShowConfetti(true); + const handleGetStarted = React.useCallback(() => { + setAppState(prev => ({ ...prev, showConfetti: true })); + setTimeout(() => { - setShowConfetti(false); - setShowLanding(false); - }, 4000); - } - + setAppState(prev => ({ + ...prev, + showConfetti: false, + showLanding: false, + })); + }, CONFETTI_DURATION); + }, []); - const handleSearchTrailer = (event) => { + const handleSearchTrailer = React.useCallback((event) => { event.preventDefault(); - // Filter movies based on the search term const filtered = movies.filter((movie) => - movie.title.toLowerCase().includes(searchTerm.toLowerCase()) + movie.title.toLowerCase().includes(appState.searchTerm.toLowerCase()) ); - setFilteredMovies(filtered); - setNoResults(filtered.length === 0); - }; + + setAppState(prev => ({ + ...prev, + filteredMovies: filtered, + noResults: filtered.length === 0, + })); + }, [appState.searchTerm]); + + const handleSetSearchTerm = React.useCallback((term) => { + setAppState(prev => ({ ...prev, searchTerm: term })); + }, []); + + const handleSelectMovie = React.useCallback((movie) => { + setAppState(prev => ({ ...prev, selectedMovie: movie })); + }, []); + + const toggleTrailer = React.useCallback((value) => { + setAppState(prev => ({ ...prev, playTrailer: value })); + }, []); React.useEffect(() => { // Set the selected movie to the first movie when the component is mounted if (filteredMovies.length > 0) { - setSelectedMovie(filteredMovies[0]); + setAppState(prev => ({ ...prev, selectedMovie: filteredMovies[0] })); } else { - setSelectedMovie({}); + setAppState(prev => ({ ...prev, selectedMovie: {} })); } }, [filteredMovies]); From a10ba32b683e7d01b826a34c51f35dca08d308af Mon Sep 17 00:00:00 2001 From: Mitchell Date: Sun, 3 Nov 2024 00:47:03 +0200 Subject: [PATCH 4/4] Add correct render --- src/App.js | 129 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 74 insertions(+), 55 deletions(-) diff --git a/src/App.js b/src/App.js index 708dcb5..2212b8e 100644 --- a/src/App.js +++ b/src/App.js @@ -44,7 +44,7 @@ function App() { const handleGetStarted = React.useCallback(() => { setAppState(prev => ({ ...prev, showConfetti: true })); - + setTimeout(() => { setAppState(prev => ({ ...prev, @@ -59,7 +59,7 @@ function App() { const filtered = movies.filter((movie) => movie.title.toLowerCase().includes(appState.searchTerm.toLowerCase()) ); - + setAppState(prev => ({ ...prev, filteredMovies: filtered, @@ -88,64 +88,83 @@ function App() { } }, [filteredMovies]); - const renderTrailer = (trailer) => { - const opts = { - height: 500, - width: '100%', - playerVars: { - autoplay: 1, - controls: 0, - }, - }; - - return ( -
- setPlayTrailer(false)} - /> + const renderTrailer = () => ( +
+ toggleTrailer(false)} + /> +
+ ); + + + const renderMovieContent = () => ( + <> +
+
+
+ {playTrailer && ( + + )} + + {selectedMovie.trailer && playTrailer && renderTrailer()} + + + +

{selectedMovie.title}

+

+ {selectedMovie.description} +

+
- ) - } + + {noResults ? ( + + ) : ( +
+ {filteredMovies.map((movie) => ( + + ))} +
+ )} + + ); return ( -
+
{showLanding ? ( - + ) : ( - <> -
-
-
- {playTrailer ? - : null} - {selectedMovie.trailer && playTrailer ? renderTrailer(selectedMovie.trailer) : null} - -

{selectedMovie.title}

-

{selectedMovie.description}

-
-
- - {noResults ? ( - - ) : ( -
- {filteredMovies.map((movie, index) => ( - - ))} -
- )} - + renderMovieContent() )}
);