Skip to content

CSES-Open-Source/cohorts-wi26-week3-react

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 

Repository files navigation

Cohorts Week 3: Movie Search App with React

First, create a fork and clone the project from Github. Clone as a folder called moviesearch:

git clone https://github.com/CSES-Open-Source/cohorts-wi26-week3-react.git moviesearch

PREREQUISITES

Node.js and npm


Install Node.js (Required for Vite)

Before starting, make sure you have Node.js v18+ installed. You can check by running:

node -v

If you see a version number like v23.3.0, you’re ready to continue. If not, follow the steps below based on your operating system.


macOS Example.

  1. Install Node with Homebrew (recommended)

    brew install node
  2. Verify installation

    node -v
    npm -v

    You should now see version numbers for both Node and npm.

  3. (Alternative) If you don’t use Homebrew, you can also download Node directly:

    • Go to https://nodejs.org
    • Choose LTS → macOS Installer (.pkg)
    • Follow the on-screen setup wizard

Windows Example

  1. Install Node using the official installer

    • Visit https://nodejs.org
    • Download the LTS version (.msi file)
    • Run the installer
    • Keep the default options checked — especially “Add to PATH”
  2. Verify installation Open a new Command Prompt and run:

    node -v
    npm -v

    You should see version numbers appear.

  3. (Optional for advanced users) You can also install via Chocolatey:

    choco install nodejs-lts

Viewing the application on a browser

TODO 1: Install dependencies

Move into the starter folder within moviesearch and install dependencies:

cd moviesearch/starter
npm install

About node_modules and package.json:

When you run npm install, a node_modules folder is created. This folder contains all the external code (libraries) your project needs to function.

You should always include node_modules in your .gitignore file to prevent it from being uploaded to your repository. Why?

  • It is massive: This folder can contain thousands of files and take up a lot of space, which slows down your Git operations.
  • It is redundant: Your package.json already lists every library the project needs.
  • It is reproducible: Anyone who clones your repo can simply run npm install to recreate the exact same node_modules folder on their own machine.

Start development server

You can start the development server to verify everything is working:

npm run dev

Follow the link (localhost:5173) to see the web app on a browser.


React

TODO 1: Complete MovieCard component

In components/MovieCard.jsx, complete the MovieCard component. So far, the component only displays information about the movie's title. Complete the component by adding information about the movie's year, genre, and rating.

<p>Comedy</p>

You should now be able to see a MovieCard for Ratatouille on the page.

TODO 2: Implement MovieCard Props

In React, a prop (short for "property") is a way to pass data from a parent component to a child component. Props are read-only, meaning that a child component cannot modify the props it receives from its parent.

In MovieCard.jsx, update the MovieCard function by to accept the following props: title, year, genre, rating

function MovieCard({ title, year, genre, rating }) {
}

Now, you can access these variables within MovieCard. Replace all hardcoded values (like "Ratatouille") with variables.

<p>{genre}</p>

In App.jsx, update the MovieCard that we are rendering to pass in values for title, genre, and year, rating. These values are the props that the component uses.

<MovieCard title="Ratatouille" year={2007} genre="Comedy" rating={8.1} />

TODO 3: Render multiple MovieCard components

In a real application, you won't want to manually type out every single component. Instead, you can use the JavaScript .map() function to "loop" through an array of data and transform each item into a React component.

In App.jsx, replace the single, hardcoded with a dynamic mapping of the DISNEY_MOVIES array. Note: At the top of App.jsx, DISNEY_MOVIES is imported from data/movies.js where we have mock data in the form of arrays.

<div className="movie-grid">
  {DISNEY_MOVIES.map((movie) => (
    <MovieCard 
      title={movie.title} 
      year={movie.year} 
      genre={movie.genre} 
      rating={movie.rating} 
    />
  ))}
</div>

On the page, you should now see a grid of components for all the movies in the DISNEY_MOVIES array.

The above code is a much more cleaner and efficient way of doing something like:

<div className="movie-grid">
  <MovieCard 
    title="Ratatouille" 
    year={2007}
    genre="Comedy"
    rating={8.1}
  />
  <MovieCard 
    title="Moana" 
    year={2016}
    genre="Adventure"
    rating={7.6}
  />
  {/* repeat for all other movies in DISNEY_MOVIES.... */}
</div>

TODO 4: Initialize State with useState for the search term

To make our app interactive, we need a way to "remember" what the user is typing into the search bar. In React, we use a Hook called useState to create a state variable. Whenever this variable changes, React automatically re-renders the component to reflect the new data.

In App.jsx, initialize the state at the top of your App function. We will start with an empty string "" because the search bar is empty when the page first loads.

const [searchTerm, setSearchTerm] = useState("");

searchTerm is the variable that holds the string value for what is searched. setSearchTerm is a function that we call to change the value of searchTerm.

Note that the import of useState at the top of App.jsx is required to use it in our code.


TODO 5: Connect searchTerm to the search bar

Next, we need to "connect" this searchTerm state to your search bar <input> element so that what we type in the search bar is stored in searchTerm. You need to set the value to your state variable and update that state every time the user types using the onChange event.

  • value is what we want the search bar text to be. In this case, we want it to be the same as the searchTerm value.
  • onChange lets us specify what action should occur if the input changes. Here, we want to set searchTerm to be the value typed in the search bar. e represents the onChange event, and e.target.value is how we access the the string value of what was typed in the search bar (e.g. "Ratatouille")
<input 
  className="search-bar"
  placeholder="Search for a movie..."
  value={searchTerm}
  onChange={(e) => setSearchTerm(e.target.value)}
/>

TODO 6: Filter movies based on search

Now that we are "remembering" the search term in our state, the final step is to use that term to hide movies that don't match. We do this by applying the JavaScript .filter() method to our DISNEY_MOVIES array before we map over it.

With the filter method, we only want elements in DISNEY_MOVES that include the search term in the movie title. We will also use .toLowerCase() on both the search term and the movie title so that searching for "ratatouille" or "RATATOUILLE" still finds "Ratatouille".

.filter(movie => movie.title.toLowerCase().includes(searchTerm.toLowerCase()))

We can chain the filter method with the map method as shown below:

{DISNEY_MOVIES
    .filter(movie => movie.title.toLowerCase().includes(searchTerm.toLowerCase()))
    .map(movie => (
        <MovieCard 
            key={movie.id} 
            title={movie.title} 
            year={movie.year} 
            genre={movie.genre} 
            rating={movie.rating}
        />
    ))
}

The above code first filters out movies with titles that do not match the search term. Then, we are mapping the selected movies to MovieCard components which will be rendered on our page.

Now, when you type a movie title in the search bar, the grid of movies should be automatically filtered.


CHALLENGE FEATURE!! Switch between a grid of Disney movies to a grid of Harry Potter movies

Right now, we only display a grid of Disney movies. Allow the user to click buttons to switch between viewing a grid of Disney movies and a grid of Harry Potter movies.

Note: array with Harry Potter movies data can be found in data/movies.js and imported the same way that DISNEY_MOVIES was imported in App.jsx

Steps:

  1. In a file components/button.jsx, create a reusable button component with a prop for the button's text (e.g. Disney, Harry Potter). You can also add CSS for the button in App.css.
  2. In App.jsx, display one button component with the text "Disney" and one with "Harry Potter"
  3. When the "Disney" button is clicked, we will use DISNEY_MOVIES for our movies list. When the "Harry Potter" button is clicked, we will use HARRY_POTTER_MOVIES for our movies list. Implement this using useState() to hold the correct movies array and the onClick event in the buttons.

Hint for #3: The button component (child) can't reach "up" into the parent component App (located in App.jsx) to change the movie array state variables directly. Instead, pass a function down to the button component as a prop. When the button component triggers that function during onClick events, it's like sending a signal back up to App.jsx to update the state!


Uploading Your Work

To upload your work to your GitHub repository, follow these steps:

TODO 1: Add Changes

In your terminal, navigate to the directory of your project and run the following command to stage all your changes:

```bash
git add .

TODO 2: Commit Changes

Next, commit your changes with a descriptive message:

git commit -m <message>

TODO 3: Push Changes

Finally, push your changes to your GitHub repository:

git push origin main

This will upload your committed changes to the main branch of your remote repository on GitHub.


Congrats!

You have successfully completed the React Movie Search App project! 🎉

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors