React JS Crash Course 2023 - Build an Movie App in 1 Hour [ Easiest way ]

    By: Manu
    5 months ago

    React is a powerful JavaScript library for building user interfaces, and it revolves around the concept of components. Components are the building blocks of a React application, allowing you to create reusable and modular pieces of UI. In this blog post, we will explore two fundamental hooks in React, `useState` and `useEffect`, which are essential for managing component state and handling side effects.


    Understanding React Components


    Before we dive into `useState` and `useEffect`, let's take a moment to understand React components. A component in React is a self-contained, reusable piece of UI that can manage its own state and lifecycle. Components can be divided into two categories: functional components and class components.


    Functional components, introduced in React 16.8, are defined as JavaScript functions. They are simpler and more concise than class components. To manage state and side effects in functional components, we use hooks like `useState` and `useEffect`.


    Managing State with `useState`


    State is a crucial concept in React. It represents the data that can change over time in a component. The `useState` hook is used to declare state variables in functional components. Here's how it works:


    import React, { useState } from 'react';
    
    function Counter() {
     const [count, setCount] = useState(0);
    
     return (
      <div>
       <p>Count: {count}</p>
       <button onClick={() => setCount(count + 1)}>Increment</button>
      </div>
     );
    }
    



    In this example, we use `useState` to declare a state variable `count` and a function `setCount` to update its value. This state variable persists across re-renders, allowing you to maintain and modify component state.


    Handling Side Effects with `useEffect`


    Side effects in React refer to actions that occur outside the normal data flow, such as fetching data from an API or interacting with the DOM. The `useEffect` hook is designed to manage side effects in functional components. Here's a basic example:



    import React, { useState, useEffect } from 'react';
    
    function RandomNumber() {
     const [number, setNumber] = useState(null);
    
     useEffect(() => {
      const randomNum = Math.floor(Math.random() * 100);
      setNumber(randomNum);
     }, []);
    
     return <p>Random Number: {number}</p>;
    }
    



    In this example, the `useEffect` hook runs once after the component is mounted. It generates a random number and updates the state variable `number`. The empty dependency array `[]` ensures that the effect only runs once.


    Combining `useState` and `useEffect`


    Often, you'll need to combine `useState` and `useEffect` to manage state and side effects in your components. Here's a more complex example:


    import React, { useState, useEffect } from 'react';
    
    function WeatherDisplay({ city }) {
     const [weather, setWeather] = useState(null);
    
     useEffect(() => {
      // Fetch weather data from an API based on the 'city' prop
      fetch(`https://api.weather.com/${city}`)
       .then((response) => response.json())
       .then((data) => setWeather(data));
     }, [city]);
    
     return (
      <div>
       <h2>Weather in {city}</h2>
       <p>Temperature: {weather?.temperature}°C</p>
       <p>Condition: {weather?.condition}</p>
      </div>
     );
    }
    


    In this example, we use `useState` to manage the `weather` state and `useEffect` to fetch weather data when the `city` prop changes. This demonstrates how these two hooks can be combined to create a dynamic and data-driven component.


    Code used in video: Mainly App.js reset can be downloaded from zip file.

    import { useState, useEffect } from "react";
    
    
    function App() {
      let typeingTimer;
      const [theme, setTheme] = useState(false);
      const [searchKeyWord, setSearchKeyWord] = useState("batman");
      const baseUrl = "https://www.omdbapi.com/?apikey=cf2f99b7&";
      const [movies, setMovies] = useState([]);
      const [totalPages, setTotalPages] = useState(0);
      const [currentPage, setCurrentPage] = useState(1);
      const [totalMovieCount, setTotalMovieCount] = useState(0);
    
    
      const getSearchResults = (event) => {
        clearTimeout(typeingTimer);
        let keyword = event.target.value;
        if (keyword.length >= 4) {
          typeingTimer = setTimeout(() => {
            setSearchKeyWord(keyword);
          }, 2000);
        }
      };
    
    
      const getMovies = async (keyword, pageNumber = 0) => {
        try {
          let fullUrl;
    
    
          if (pageNumber) {
            fullUrl = baseUrl + `s=${keyword}` + `&page=${pageNumber}`;
          } else {
            fullUrl = baseUrl + `s=${keyword}`;
          }
    
    
          const response = await fetch(fullUrl);
          const data = await response.json();
          console.log(data);
          setMovies(data);
          setTotalMovieCount(data.totalResults);
        } catch (error) {
          console.error(error);
        }
      };
    
    
      const handlePageClick = (page) => {
        setCurrentPage(page);
      };
    
    
      const renderPaginationLinks = () => {
        const links = [];
        let totalLocalPages;
        if (totalPages >= 10) {
          totalLocalPages = 10;
        } else {
          totalLocalPages = totalPages;
        }
    
    
        for (let page = 1; page <= totalLocalPages; page++) {
          links.push(
            <a
              key={page}
              href="#"
              className={currentPage === page ? "active" : ""}
              onClick={() => handlePageClick(page)}
            >
              {page}
            </a>
          );
        }
        return links;
      };
    
    
      useEffect(() => {
        setTotalPages(Math.round(totalMovieCount / 10));
      }, [totalMovieCount]);
    
    
      useEffect(() => {
        getMovies(searchKeyWord, currentPage);
      }, [searchKeyWord, currentPage]);
    
    
      return (
        <div className={`app ${theme ? "dark" : "light"}`}>
          <div className="logo">
            <img src={"/movies.png"} alt="movie application" />
          </div>
          <div className="header">
            <div className="link">
              <button className="button">
                {theme ? (
                  <img
                    width="50px"
                    src={"/moon.png"}
                    alt="image of moon"
                    onClick={() => setTheme(!theme)}
                  />
                ) : (
                  <img
                    width="50px"
                    src={"/sun.png"}
                    alt="image of sun"
                    onClick={() => setTheme(!theme)}
                  />
                )}
              </button>
            </div>
          </div>
          <div className="containerWrapper">
            <input
              type="text"
              className="searchInput"
              placeholder={"Search Movie Here"}
              onChange={(event) => getSearchResults(event)}
            />
    
    
            <div className="pagination">
              <a href="#" 
                onClick={() => setCurrentPage((prev) => prev - 1)}>
                   &laquo;
                </a>
              {renderPaginationLinks()}
              <a href="#" 
                onClick={() => setCurrentPage((prev) => prev + 1)}>
                  &raquo;
                </a>
              </div>
          </div>
          <div className="movieList">
            {movies["Search"] &&
              movies["Search"].map((movie, index) => {
                return (
                  <div className="movieCard" key={movie.imdbID}>
                    <img
                      src={movie.Poster != "N/A" ? movie.Poster : "/default.png"}
                    />
                    <div className="container">
                      <h3>
                        {movie.Title} ({movie.Year})
                      </h3>
                    </div>
                  </div>
                );
              })}
          </div>
        </div>
      );
    }
    
    
    export default App;
    


    Understanding and mastering `useState` and `useEffect` is crucial for developing React applications. These hooks empower you to manage state and handle side effects in functional components efficiently. By incorporating these concepts into your projects, you can build dynamic, interactive, and responsive user interfaces with ease. As you continue your journey with React, remember that practice and experimentation are key to becoming a proficient React developer. Happy coding!