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
The code in the effect part is wrong
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
andmovieId
field to generate theisFavorited
state.You can solve this either two ways
or even shorted
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).
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.