I have added a new context component MovieContext.js
, but it is causing an uncaught type error. I had a look online and it is apparently caused when trying to render multiple children. This I do not understand because as far as I can workout I am only trying to render one.
Error
react-dom.development.js:18747 Uncaught TypeError: render is not a function
at updateContextConsumer (react-dom.development.js:18747:1)
at beginWork (react-dom.development.js:19114:1)
at HTMLUnknownElement.callCallback (react-dom.development.js:3945:1)
at Object.invokeGuardedCallbackDev (react-dom.development.js:3994:1)
at invokeGuardedCallback (react-dom.development.js:4056:1)
at beginWork$1 (react-dom.development.js:23964:1)
at performUnitOfWork (react-dom.development.js:22776:1)
at workLoopSync (react-dom.development.js:22707:1)
at renderRootSync (react-dom.development.js:22670:1)
at performSyncWorkOnRoot (react-dom.development.js:22293:1)
react_devtools_backend.js:3973 The above error occurred in the <Context.Consumer> component:
at EventProvider (http://localhost:3000/static/js/bundle.js:4485:5)
at OptionProvider (http://localhost:3000/static/js/bundle.js:4874:5)
at UserProvider (http://localhost:3000/static/js/bundle.js:5042:5)
at AuthProvider (http://localhost:3000/static/js/bundle.js:4303:5)
at Router (http://localhost:3000/static/js/bundle.js:96142:5)
at BrowserRouter (http://localhost:3000/static/js/bundle.js:95659:5)
at App
at InnerThemeProvider (http://localhost:3000/static/js/bundle.js:37635:70)
at ThemeProvider (http://localhost:3000/static/js/bundle.js:37342:5)
at ThemeProvider (http://localhost:3000/static/js/bundle.js:37655:5)
MovieContext.js
import { createContext, useState, useEffect, useContext } from "react";
import jwt_decode from "jwt-decode";
import useFetch from "../hooks/useFetch";
import { useNavigate } from "react-router-dom";
import AuthContext from "./AuthContext";
import EventContext from "./EventContext";
const MovieContext = createContext();
export default MovieContext;
export const MovieProvider = ({ children }) => {
let { user } = useContext(AuthContext);
let { trainMeetingRecommendation } = useContext(EventContext)
let api = useFetch;
const [movie, setMovie] = useState("");
const [rating, setRating] = useState({
user: user.user_id,
movie: 0,
score: null,
});
const [recommendedMovies, setRecommendedMovies] = useState([]);
const [watchedMovies, setWatchedMovies] = useState([]);
// useEffect(() => {
// getRecommendedMovies();
// getWatchedMovies();
// }, []);
let getWatchedMovies = async () => {
let { response, data } = await api(`/watched_list/`, "GET");
if (response.status === 200) {
setWatchedMovies(data);
}
};
let addToWatchedList = async (id) => {
let { response, data } = await api(`/add_watched_movie/${id}`, "POST", {
movie: id,
user: user.user_id,
});
};
let editRating = async (id) => {
let { response, data } = await api(`/edit_rating/${id}`, "PUT", {
user: user.user_id,
movie: id,
score: rating.score,
});
if (response.status === 200) {
setRating(data);
} else {
setRating({ user: user.user_id, movie: id, score: 0.0 });
console.log(rating.score);
}
};
let getRating = async (id) => {
let { response, data } = api(`/get_rating/${id}`, "GET");
if (response.status === 200) {
setRating(data);
} else if (response.status === 400) {
setRating({ user: user.user_id, movie: id, score: 0.0 });
console.log(rating.score);
} else {
setRating({ user: user.user_id, movie: id, score: 0.0 });
console.log(rating.score);
}
};
let getRecommendedMovies = async () => {
let { response, data } = api(`/rec_movies/`, "GET");
if (response.status === 200) {
setRecommendedMovies(data);
} else {
alert("Something went wrong");
}
};
let trainMovieRecommendation = async () => {
let { response, data } = api(`/train/movie/`, "GET");
};
let AddRating = async (id, ratingScore) => {
let { response, data } = await api(`/add_rating/${id}`, "POST", {
user: user.user_id,
movie: id,
score: ratingScore,
});
if (response.status === 200) {
setRating(data);
}
trainMovieRecommendation();
trainMeetingRecommendation();
};
let contextData = {
movie: movie,
rating: rating,
recommendedMovies: recommendedMovies,
watchedMovies: watchedMovies,
setMovie: setMovie,
setRating: setRating,
setRecommendedMovies: setRecommendedMovies,
setWatchedMovies: setWatchedMovies,
getWatchedMovies: getWatchedMovies,
addToWatchedList: addToWatchedList,
getRating: getRating,
editRating: editRating,
getRecommendedMovies: getRecommendedMovies,
AddRating: AddRating,
};
return (
<MovieContext.Provider value={contextData}>
{children}
</MovieContext.Provider>
);
};
Movies.js
import React, { useState, useContext, useEffect } from "react";
import {
Tooltip,
IconButton,
Box,
Collapse,
TextField,
Grid,
Typography,
Rating,
Stack,
ListItem,
} from "@mui/material";
import Card from "@mui/material/Card";
import CardHeader from "@mui/material/CardHeader";
import CardMedia from "@mui/material/CardMedia";
import { moviesWithPoster } from "../data/DummyMoviesData";
import SearchIcon from "@mui/icons-material/Search";
import CloseIcon from "@mui/icons-material/Close";
import "../../styling/pages/Movies.css";
import moviePoster from "../../styling/images/empty_movie_poster.png";
import MovieContext from "../../components/helper/context/MovieContext";
import FormButton from "../../components/FormButton";
import HomePageTitle from "../../components/HomePageTitle";
import TextButton from "../../components/TextButton";
const Movies = () => {
let {
movie,
rating,
recommendedMovies,
watchedMovies,
setMovie,
setRating,
setRecommendedMovies,
setWatchedMovies,
getWatchedMovies,
addToWatchedList,
getRating,
getRecommendedMovies,
AddRating,
} = useContext(MovieContext);
const [openSearch, setOpenSearch] = React.useState(false);
const toggleSearch = () => {
setOpenSearch(!openSearch);
};
const openSearchCollapse = () => {
setOpenSearch(true);
};
const [searchValue, setSearchValue] = useState("");
return (
<>
<HomePageTitle title={"movies"} />
<Grid
container
justifyContent={"center"}
alignItems={"flex-start"}
spacing={2}
padding={2}
>
<Grid item xs={12}>
<TextField
label={"search"}
fullWidth
value={searchValue}
placeholder={"search for a movie"}
onChange={(event) => {
setSearchValue(event.target.value);
}}
InputProps={{
endAdornment: (
<TextButton
text={openSearch ? "close" : "open"}
onClick={toggleSearch}
/>
),
}}
/>
</Grid>
<Grid item xs={12}>
<Collapse in={openSearch}>
<div className={"home-page-card-background"}>
<Grid container direction={"row"} padding={2} spacing={2}>
<Grid item xs={12}>
<h5 className={"home-page-card-title"}>search result</h5>
</Grid>
<Grid item xs={12}>
<Grid
container
direction={"row"}
spacing={2}
alignItems={"center"}
>
{/* LIST OF ALL MOVIES */}
{moviesWithPoster
.filter((movie) => {
if (
movie.title
.toLowerCase()
.includes(searchValue.toLowerCase())
) {
return movie;
}
})
.map((movie) => {
return (
<Grid item>
<Card sx={{ width: 180 }}>
<CardMedia
component="img"
image={moviePoster}
alt={movie.title}
/>
<Stack
spacing={1}
padding={1}
alignItems={"center"}
>
<Rating
name="simple-controlled"
sx={{ fontSize: "1.2em" }}
precision={0.5}
max={5}
// onChange={(event, newValue) => (this.setState({score: newValue, onChange: this.fetchAddRating(movie.id)}))}
/>
<Tooltip
title={movie.title}
placement="top-start"
>
<Typography noWrap>{movie.title}</Typography>
</Tooltip>
<FormButton text={"watch"} />
</Stack>
</Card>
</Grid>
);
})}
</Grid>
</Grid>
</Grid>
</div>
</Collapse>
</Grid>
<Grid item xs={12}>
<div className={"home-page-card-background"}>
<Grid container direction={"row"} padding={2} spacing={2}>
<Grid item xs={12}>
<h5 className={"home-page-card-title"}>club movies</h5>
</Grid>
<Grid item xs={12}>
<Stack direction={"row"} overflow={"auto"}>
{moviesWithPoster.map((movie) => {
return (
<ListItem sx={{ p: 1 }}>
<Card sx={{ width: 150 }}>
<CardMedia
component="img"
sx={{ height: "100%" }}
image={moviePoster}
alt={movie.title}
/>
<Stack spacing={1} padding={1} alignItems={"center"}>
<Rating
name="simple-controlled"
sx={{ fontSize: "1.2em" }}
precision={0.5}
max={5}
// onChange={(event, newValue) => (this.setState({score: newValue, onChange: this.fetchAddRating(movie.id)}))}
/>
<Tooltip title={movie.title} placement="top-start">
<Typography noWrap>{movie.title}</Typography>
</Tooltip>
<FormButton text={"watch"} />
</Stack>
</Card>
</ListItem>
);
})}
</Stack>
</Grid>
</Grid>
</div>
</Grid>
<Grid item xs={12}>
<div className={"home-page-card-background"}>
<Grid container direction={"row"} padding={2} spacing={2}>
<Grid item xs={12}>
<h5 className={"home-page-card-title"}>recommended</h5>
</Grid>
<Grid item xs={12}>
<Stack direction={"row"} overflow={"auto"}>
{recommendedMovies.map((movie) => {
return (
<ListItem sx={{ p: 1 }}>
<Card sx={{ width: 150 }}>
<CardMedia
component="img"
sx={{ height: "100%" }}
image={moviePoster}
alt={movie.title}
/>
<Stack spacing={1} padding={1} alignItems={"center"}>
<Rating
name="simple-controlled"
sx={{ fontSize: "1.2em" }}
precision={0.5}
max={5}
onChange={(event, newValue) =>
setRating({
score: newValue,
onChange: AddRating(movie.id, newValue),
})
}
/>
<Tooltip title={movie.title} placement="top-start">
<Typography noWrap>{movie.title}</Typography>
</Tooltip>
<FormButton
text={"watch"}
onClick={() => {
addToWatchedList(movie.id);
}}
onChange={() => {
getRecommendedMovies();
}}
/>
</Stack>
</Card>
</ListItem>
);
})}
</Stack>
</Grid>
</Grid>
</div>
</Grid>
<Grid item xs={12}>
<div className={"home-page-card-background"}>
<Grid container direction={"row"} padding={2} spacing={2}>
<Grid item xs={12}>
<h5 className={"home-page-card-title"}>watched</h5>
</Grid>
<Grid item xs={12}>
<Stack direction={"row"} overflow={"auto"}>
{watchedMovies.map((movie) => {
return (
<ListItem sx={{ p: 1 }}>
<Card sx={{ width: 150 }}>
<CardMedia
component="img"
sx={{ height: "100%" }}
image={moviePoster}
alt={movie.title}
/>
<Stack spacing={1} padding={1} alignItems={"center"}>
<Rating
name="simple-controlled"
sx={{ fontSize: "1.2em" }}
precision={0.5}
max={5}
// onChange={(event, newValue) => (this.setState({score: newValue, onChange: this.fetchAddRating(movie.id)}))}
/>
<Tooltip title={movie.title} placement="top-start">
<Typography noWrap>{movie.title}</Typography>
</Tooltip>
<FormButton text={"watch"} />
</Stack>
</Card>
</ListItem>
);
})}
</Stack>
</Grid>
</Grid>
</div>
</Grid>
</Grid>
</>
);
};
export default Movies;
App.js
import React, { useEffect, useContext } from "react";
import "../../styling/pages/App.css";
import Navbar from "../../components/root/Navbar";
import HomePage from "../root/Homepage";
import LogIn from "../root/Login";
import Logout from "../root/Logout";
import NotFound404 from "../root/NotFound";
import Profile from "../home/Profile";
import {
useLocation,
BrowserRouter as Router,
Routes,
Route,
} from "react-router-dom";
import Signup from "../root/Signup";
import HomeRouter from "./HomeRouter";
import Clubs from "../home/Clubs";
import Movies from "../home/Movies";
import Options from "../home/Options";
import Home from "../home/Home";
import OthersProfile from "../../components/OthersProfile";
import PrivateRoute from "../../components/helper/PrivateRoute";
import { AuthProvider } from "../../components/helper/context/AuthContext";
import { UserProvider } from "../../components/helper/context/UserContext";
import ClubDetail from "../../components/ClubDetail";
import NewClub from "../../components/NewClubForm";
import Discussion from "../home/Discussion";
import NewEvent from "../../components/NewEventForm";
import ClubDiscussion from "../../components/ClubDiscussion";
import ShowEvent from "../../components/ShowEvent";
import { OptionProvider } from "../../components/helper/context/OptionContext";
import { EventProvider } from "../../components/helper/context/EventContext";
import MovieProvider from "../../components/helper/context/MovieContext";
function App() {
return (
<Router>
<AuthProvider>
<UserProvider>
<OptionProvider>
<EventProvider>
<MovieProvider>
<Navbar />
<Routes>
<Route path={"/"} element={<HomePage />} />
<Route path={"/login"} element={<LogIn />} />
<Route path={"/signup"} element={<Signup />} />
<Route path={"/logout"} element={<Logout />} />
<Route
path={"/home"}
element={
<PrivateRoute>
<HomeRouter />
</PrivateRoute>
}
>
<Route index element={<Home />} />
<Route path={"logout"} element={<Logout />} />
<Route path={"profile"} element={<Profile />} />
<Route path={"movies"} element={<Movies />} />
<Route path={"clubs"} element={<Clubs />}>
<Route path={":clubID"} element={<ClubDetail />}>
<Route path={":userID"} element={<OthersProfile />} />
</Route>
<Route path={"clubs/new"} element={<NewClub />} />
</Route>
<Route path={"discussion"} element={<Discussion />}>
<Route path={":clubID"} element={<ClubDiscussion />}>
<Route index element={<ShowEvent />} />
<Route path={"new"} element={<NewEvent />} />
</Route>
</Route>
<Route path={"options"} element={<Options />} />
</Route>
<Route path={"*"} element={<NotFound404 />} />
</Routes>
</MovieProvider>
</EventProvider>
</OptionProvider>
</UserProvider>
</AuthProvider>
</Router>
);
}
export default App;
Any help would be much appreciated.
CodePudding user response:
You have a named export for MovieProvider
and in the same file a default export for MovieContext;
export default MovieContext; // default export
export const MovieProvider // named export
In App.js
you are using a default import
and thus importing the MovieContext instead of the Provider.
import MovieProvider from "../../components/helper/context/MovieContext"; // default import will import MovieContext with the variable name MovieProvider
To use the named import change this :
import MovieProvider from "../../components/helper/context/MovieContext";
to this:
import {MovieProvider} from "../../components/helper/context/MovieContext";