skip to Main Content

I am trying to build client-side of an app using React with existing server-side code (REST API and database) .

Currently, trying to create a profile view and allowing users to add/remove movies from favourite.
There’s movie-card.jsx and movie-view.jsx.

I’m trying to allow user to add/remove movies from user profile under movie-view.

Now user able to add/remove movies. But the problem is after clicking add/remove movies and click go to profile, the error appears.
If i refresh the page and go to profile, the favourite movies list is actually updated.

Another problem is, when updating profile for example, update password. Previously was hashedpassword, after updating, it became not encrypted which when i login after updating, it says no such user.

How do i avoid that?

Provided my github pull link from a new branch.

https://github.com/joannawongww/myFlix-client/pull/4

movie-view.jsx:

import {
  useEffect,
  useState
} from "react";
import {
  useParams
} from "react-router";
import {
  Link
} from "react-router-dom";
import PropTypes from "prop-types";
import "./movie-view.scss";
import Button from "react-bootstrap/Button";
import {
  ProfileView
} from "../profile-view/profile-view";

export const MovieView = ({
  user,
  token,
  movies,
  setUser
}) => {
  const {
    movieId
  } = useParams();
  const [Favorite, setFavorite] = useState(false);

  useEffect(() => {
    if (user ? .Favorite ? .length && movieId) {
      setFavorite(user.Favorite.includes(movieId));
    }
    // const isFavorited = user.Favorite.includes(movieId);
    // setFavorite(isFavorited);
  }, [user.Favorite, movieId]);

  const addFavorite = () => {
    fetch(
        `https://myflix-jwww-f51e9c501b1f.herokuapp.com/users/${user.Username}/movies/${movieId}`, {
          method: "PUT",
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${token}`,
          },
        }
      )
      .then((response) => {
        if (response.ok) {
          return response.json();
        }
      })
      .then((data) => {
        setFavorite(true);
        localStorage.setItem("user", JSON.stringify(data));
        setUser(data);
      });
  };

  const removeFavorite = () => {
    fetch(
        `https://myflix-jwww-f51e9c501b1f.herokuapp.com/users/${user.Username}/movies/${movieId}`, {
          method: "DELETE",
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${token}`,
          },
        }
      )
      .then((response) => {
        if (response.ok) {
          return response.json();
        }
      })
      .then((data) => {
        setFavorite(false);
        localStorage.setItem("user", JSON.stringify(data));
        setUser(data);
      });
  };

  const movie = movies.find((movie) => movie.id === movieId);

  return ( <
    div >
    <
    div >
    <
    span >
    <
    img src = {
      movie.ImagePath
    }
    width = "30%" / >
    <
    /span> <
    /div>

    <
    div >
    <
    span > Title: < /span> <
    span > {
      movie.Title
    } < /span> <
    /div>

    <
    div >
    <
    span > Description: < /span> <
    span > {
      movie.Description
    } < /span> <
    /div>

    <
    div >
    <
    span > Genre: < /span> <
    span > {
      movie.Genre
    } < /span> <
    /div>

    <
    div >
    <
    span > Director: < /span> <
    span > {
      movie.Director
    } < /span> <
    /div>

    <
    div >
    <
    span > Featured: < /span> <
    span > {
      movie.Featured
    } < /span> <
    /div>

    {
      Favorite ? ( <
        Button onClick = {
          removeFavorite
        } > Remove from favourite movies < /Button>
      ) : ( <
        Button onClick = {
          addFavorite
        } > Add to my favorite movies < /Button>
      )
    }

    <
    Link to = {
      `/`
    } >
    <
    Button > Back < /Button> <
    /Link> <
    /div>
  );
};

main-view.jsx

import React, { useState, useEffect } from "react";
import { MovieCard } from "../movie-card/movie-card";
import { MovieView } from "../movie-view/movie-view";
import { LoginView } from "../login-view/login-view";
import { SignupView } from "../signup-view/signup-view";
import { ProfileView } from "../profile-view/profile-view";
import { NavigationBar } from "../navigation-bar/navigation-bar";
import Row from "react-bootstrap/Row";
import Col from "react-bootstrap/Col";
import Container from "react-bootstrap/Container";
import Button from "react-bootstrap/Button";
import { Navbar, Container, Nav } from "react-bootstrap";
import { BrowserRouter, Routes, Route, Navigate } from "react-router-dom";

export const MainView = () => {
  const [movies, setMovies] = useState([]);
  const [user, setUser] = useState(null);
  const [token, setToken] = useState(null);
  const storedUser = JSON.parse(localStorage.getItem("user"));
  const storedToken = localStorage.getItem("token");

  const onLogout = () => {
    setUser(null);
    setToken(null);
    localStorage.clear();
  };

  useEffect(() => {
    if (!token) {
      return;
    }

    fetch("https://myflix-jwww-f51e9c501b1f.herokuapp.com/movies", {
      headers: {
        Authorization: `Bearer ${token}`,
      },
    })
      .then((response) => response.json())
      .then((data) => {
        console.log(data);

        const moviesFromApi = data.map((movie) => {
          return {
            id: movie._id,
            Title: movie.Title,
            Description: movie.Description,
            ImagePath: movie.ImagePath,
            Genre: movie.Genre.Name,
            Director: movie.Director.Name,
            Featured: movie.Featured.toString(),
          };
        });
        setMovies(moviesFromApi);
      });
  }, [token]);

  return (
    <BrowserRouter>
      <NavigationBar
        user={user}
        onLoggedOut={() => {
          setUser(null);
        }}
      />{" "}
      <Row className="justify-content-md-center">
        <Routes>
          <Route
            path="/signup"
            element={
              <>
                {" "}
                {user ? (
                  <Navigate to="/" />
                ) : (
                  <Col md={5}>
                    <SignupView />
                  </Col>
                )}{" "}
              </>
            }
          />
          <Route
            path="/login"
            element={
              <>
                {" "}
                {user ? (
                  <Navigate to="/" />
                ) : (
                  <Col md={5}>
                    <LoginView
                      onLoggedIn={(user, token) => {
                        setUser(user);
                        setToken(token);
                      }}
                    />{" "}
                  </Col>
                )}{" "}
              </>
            }
          />
          <Route
            path="/profile"
            element={
              <>
                {" "}
                {!user ? (
                  <Navigate to="/login" replace />
                ) : (
                  <Col>
                    <ProfileView
                      user={user}
                      token={token}
                      setUser={setUser}
                      movies={movies}
                      onLogout={onLogout}
                    />{" "}
                  </Col>
                )}{" "}
              </>
            }
          />
          <Route
            path="/movies/:movieId"
            element={
              <>
                {" "}
                {!user ? (
                  <Navigate to="/login" replace />
                ) : movies.length === 0 ? (
                  <Col> List is empty! </Col>
                ) : (
                  <Col md={8}>
                    <MovieView
                      movies={movies}
                      user={user}
                      setUser={setUser}
                      token={token}
                    />{" "}
                  </Col>
                )}{" "}
              </>
            }
          />
          <Route
            path="/"
            element={
              <>
                {" "}
                {!user ? (
                  <Navigate to="/login" replace />
                ) : movies.length === 0 ? (
                  <Col> List is empty! </Col>
                ) : (
                  <>
                    {" "}
                    {movies.map((movie) => (
                      <Col className="mb-4" key={movie.id} md={3}>
                        <MovieCard movie={movie} />{" "}
                      </Col>
                    ))}{" "}
                  </>
                )}{" "}
              </>
            }
          />{" "}
        </Routes>{" "}
      </Row>{" "}
    </BrowserRouter>
  );
};

2

Answers


  1. The code in the effect part is wrong

    useEffect(() => {
        const isFavorited = user.FavoriteMovies.includes(movieId);
        setFavorite(isFavorited);
      }, []);
    

    Here, you have initialized the useEffect with empty dependencies. So it will fire as soon as the component mounts. But you are relaying on the user and movieId field to generate the isFavorited state.

    You can solve this either two ways

    1. To update dependencies and if condition
    React.useEffect(() => {
        if(user?.FavoriteMovies?.length && movieId) {
           setFavorite(user.FavoriteMovies.includes(movieId));
        }
      }, [user.FavoriteMovies, movieId]);
    
    1. Using React.useMemo()
    const Favorited = React.useMemo(() => {
        if(user?.FavoriteMovies?.length && movieId) {
           return user.FavoriteMovies.includes(movieId)
        }
        return false;
    },
    [user.FavoriteMovies, movieId]);
    

    or even shorted

    const Favorited = React.useMemo(() => 
       (user?.FavoriteMovies || [])?.includes(movieId),
    [user.FavoriteMovies, movieId]);
    
    Login or Signup to reply.
  2. These errors tell you a couple things. There is an undefined variable in your code, and you are treating it as valid data (with properties).

        const isFavorited = user.FavoriteMovies.includes(movieId);
    

    In this case, "user.FavoriteMovies" is undefined. As such, you cannot access the property ".includes". Your solution would be to handle cases where the user.FavoriteMovies property is undefined.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search