**can someone help me why my project run a alots error about this?
I don't see any question about my codes.
Here is error:
Warning: Maximum update depth exceeded. This can happen when a component calls setState inside useEffect, but useEffect either doesn't have a dependency array, or one of the dependencies changes on every render.
at Navigate (http://localhost:3000/static/js/bundle.js:161563:5)
at div
at O (http://localhost:3000/static/js/bundle.js:168705:6)
at div
at O (http://localhost:3000/static/js/bundle.js:168705:6)
at div
at O (http://localhost:3000/static/js/bundle.js:168705:6)
at Product (http://localhost:3000/static/js/bundle.js:1761:5)
at section
at O (http://localhost:3000/static/js/bundle.js:168705:6)
at Products
at div
at O (http://localhost:3000/static/js/bundle.js:168705:6)
at ProductList
at RenderedRoute (http://localhost:3000/static/js/bundle.js:161243:5)
at Routes (http://localhost:3000/static/js/bundle.js:161692:5)
at Router (http://localhost:3000/static/js/bundle.js:161623:15)
at BrowserRouter (http://localhost:3000/static/js/bundle.js:159844:5)
at App
here are the relative codes:
App.jsx.
This one is setting path for the route.
import React from 'react'
import Cart from './pages/Cart'
import Home from './pages/Home'
import Login from './pages/Login'
import Product from './pages/Product'
import ProductList from './pages/ProductList'
import Register from './pages/Register'
import { BrowserRouter as Router, Navigate, Route, Routes } from "react-router-dom";
const App = () => {
const user = true;
return (
<Router>
<Routes>
<Route exact path="/" element={<Home />} />
<Route exact path="/products/:category" element={<ProductList />} />
<Route exact path="/product/:id" element={<Product />} />
<Route exact path="/cart" element={<Cart />} />
<Route exact path="/register" element={user ? <Navigate to="/" /> : <Register />} />
<Route exact path="/login" element={user ? <Navigate to="/" /> : <Login />} />
</Routes>
</Router>
)
}
export default App
Product.jsx This one is running product information,it's also a component.
**When I run the url:http:localhost:3000/products/women,it should be show the products belongs to the category:women.**But it runs http:localhost:8000/products/productId,it's wrong.
import React from 'react'
import { useEffect, useState } from 'react';
import Product from './Product';
import axios from "axios"
const Products = ({ cate, filters, sort }) => {
//const Products = () => {
console.log(cate, filters, sort)
const [products, setProducts] = useState([]);
const [filteredProducts, setFilteredProducts] = useState([]);
useEffect(() => {
const getProducts = () => {
const res = axios.get(
cate ? `http://localhost:8000/api/products?category=${cate}`
: "http://localhost:8000/api/products")
.then(
function (res) {
setProducts(res.data);
console.log(res)
}
).catch(
function (err) {
console.log(err)
});
}
getProducts();
}, [cate]);
useEffect(() => {
cate && setFilteredProducts(
products.filter((item) => (
Object.entries(filters).every(([key, value]) => {
return item[key].includes(value);
}
)
))
)
}, [products, cate, filters])
useEffect(() => {
if ((sort === "newest")) {
setFilteredProducts((prev) =>
[...prev].sort((a, b) => a.createdAt.localeCompare(b.createdAt))
)
} else if (sort === "asc") {
setFilteredProducts((prev) =>
[...prev].sort((a, b) => a.price - b.price)
)
} else {
setFilteredProducts((prev) =>
[...prev].sort((a, b) => b.price - a.price)
)
}
})
return (
<Container >
{cate
? filteredProducts.map((item) => (
<Product item={item} key={item._id} />))
: products.slice(0, 8).map((item) => <Product item={item} key={item._id} />)}
</Container>
);
};
pages/Product.jsx.
This one is running display part.
http:localhost:3000/product/productID**
import { useLocation } from 'react-router-dom'
import { useState, useEffect } from 'react';
import { publicRequest } from './requestMethods';
const Product = () => {
// 回傳路徑
const location = useLocation();
const id = location.pathname.split("/")[2];
const [product, setProduct] = useState({});
useEffect(() => {
const getProduct = async () => {
try {
const res = await publicRequest.get("/product/find/" + id);
setProduct(res.data);
}
catch { }
}
getProduct();
}, [id])
You have to include the missing dependencies in the useEffect dependency array if not any, you can have an empty array [] as dependency
I could see a missing dep here in below effect:
useEffect(() => {
if (sort === "newest") {
setFilteredProducts((prev) =>
[...prev].sort((a, b) => a.createdAt.localeCompare(b.createdAt))
);
} else if (sort === "asc") {
setFilteredProducts((prev) => [...prev].sort((a, b) => a.price - b.price));
} else {
setFilteredProducts((prev) => [...prev].sort((a, b) => b.price - a.price));
}
},[sort]); // here `sort` is missing as dependency
Otherwise it runs on every render, which is what exactly the warning is about 😇
Related
As you can see the photo:
When I input the http:localhost:3000/ or some else url.
It all be redirected the wrong web:http:localhost:3000/product/productID
here are the relative codes:
App.jsx.
This one is setting path for the route.
import React from 'react'
import Cart from './pages/Cart'
import Home from './pages/Home'
import Login from './pages/Login'
import Product from './pages/Product'
import ProductList from './pages/ProductList'
import Register from './pages/Register'
import { BrowserRouter as Router, Navigate, Route, Routes } from "react-router-dom";
const App = () => {
const user = true;
return (
<Router>
<Routes>
<Route exact path="/" element={<Home />} />
<Route exact path="/products/:category" element={<ProductList />} />
<Route exact path="/product/:id" element={<Product />} />
<Route exact path="/cart" element={<Cart />} />
<Route exact path="/register" element={user ? <Navigate to="/" /> : <Register />} />
<Route exact path="/login" element={user ? <Navigate to="/" /> : <Login />} />
</Routes>
</Router>
)
}
export default App
Product.jsx This one is running product information,it's also a component.
When I run the url:http:localhost:3000/products/women,it should be show the products belongs to the category:women.
But it runs http:localhost:3000/products/productId,it's wrong.
import React from 'react'
import { useEffect, useState } from 'react';
import Product from './Product';
import axios from "axios"
const Products = ({ cate, filters, sort }) => {
//const Products = () => {
console.log(cate, filters, sort)
const [products, setProducts] = useState([]);
const [filteredProducts, setFilteredProducts] = useState([]);
useEffect(() => {
const getProducts = () => {
const res = axios.get(
cate ? `http://localhost:8000/api/products?category=${cate}`
: "http://localhost:8000/api/products")
.then(
function (res) {
setProducts(res.data);
console.log(res)
}
).catch(
function (err) {
console.log(err)
});
}
getProducts();
}, [cate]);
useEffect(() => {
cate && setFilteredProducts(
products.filter((item) => (
Object.entries(filters).every(([key, value]) => {
return item[key].includes(value);
}
)
))
)
}, [products, cate, filters])
useEffect(() => {
if ((sort === "newest")) {
setFilteredProducts((prev) =>
[...prev].sort((a, b) => a.createdAt.localeCompare(b.createdAt))
)
} else if (sort === "asc") {
setFilteredProducts((prev) =>
[...prev].sort((a, b) => a.price - b.price)
)
} else {
setFilteredProducts((prev) =>
[...prev].sort((a, b) => b.price - a.price)
)
}
},[sort])
return (
<Container >
{cate
? filteredProducts.map((item) => (
<Product item={item} key={item._id} />))
: products.slice(0, 8).map((item) => <Product item={item} key={item._id} />)}
</Container>
);
};
pages/Product.jsx.
This one is running display part.
http:localhost:3000/product/productID**
import { useLocation } from 'react-router-dom'
import { useState, useEffect } from 'react';
import { publicRequest } from './requestMethods';
const Product = () => {
// 回傳路徑
const location = useLocation();
const id = location.pathname.split("/")[2];
const [product, setProduct] = useState({});
useEffect(() => {
const getProduct = async () => {
try {
const res = await publicRequest.get("/product/find/" + id);
setProduct(res.data);
}
catch { }
}
getProduct();
}, [id])
ProuctList.jsx
import React from 'react'
import { mobile } from './../responsive'
import { useLocation } from 'react-router-dom';
import { useState } from 'react';
const ProductList = () => {
//回傳路徑
const location = useLocation();
const cate = location.pathname.split("/")[2];
console.log(location);
//設定selector的值,並且回傳
const [filters, setFilters] = useState({});
const [sort, setSort] = useState("newest");
const handleFilters = (e) => {
const value = e.target.value;
setFilters({
...filters,
[e.target.name]: value,
});
};
console.log(filters)
return (
<Container>
<Navbar />
<Announcement />
<Title>Dresses</Title>
<FilterContainer>
<Filter><FilterText>Filter Products:</FilterText>
<Select name="color" onChange={handleFilters}>
<Option disabled>Color</Option>
<Option>black</Option>
<Option>white</Option>
<Option>green</Option>
<Option>wheat</Option>
<Option>black</Option>
<Option>red</Option>
<Option>blue</Option>
</Select>
<Select name="size" onChange={handleFilters}>
<Option disabled>Size</Option>
<Option>XS</Option>
<Option>S</Option>
<Option>M</Option>
<Option>L</Option>
<Option>XL</Option>
</Select></Filter>
<Filter><FilterText>Sort Products:
<Select onChange={(e) => setSort(e.target.value)}>
<Option value="newest">Newest</Option>
<Option value="asc">Price(asc)</Option>
<Option value="desc">Price(desc)</Option>
</Select></FilterText></Filter>
</FilterContainer>
<Products cate={cate} filters={filters} sort={sort} />
<NewsLetter />
<Footer />
</Container>
)
}
I found that the bottom code will make the all pages redirect to the http:localhost:3000/product/productID
components/Product.jsx
const Product = ({ item }) => {
return (
<Container className='container product'>
<Circle />
<Img src={item.img} />
<Info >
<Icon >
<ShoppingCartOutlinedIcon />
</Icon>
<Icon>
<Navigate to={`/product/${item._id}`}>
<SearchOutlinedIcon />
</Navigate>
</Icon>
<Icon>
<FavoriteBorderOutlinedIcon />
</Icon>
</Info>
</Container>
)
}
The Product component is rendering a Navigate component to "/product/XXX" when it is rendered. Rendering <Navigate /> will immediately effect a navigation action. It seems this Product component is rendered as part of a list when rendering all the products. It's likely you meant to render a Link component instead so the navigation isn't effected until the search icon is clicked.
const Product = ({ item }) => {
return (
<Container className='container product'>
<Circle />
<Img src={item.img} />
<Info >
<Icon >
<ShoppingCartOutlinedIcon />
</Icon>
<Icon>
<Link to={`/product/${item._id}`}> // <-- use Link component
<SearchOutlinedIcon />
</Link>
</Icon>
<Icon>
<FavoriteBorderOutlinedIcon />
</Icon>
</Info>
</Container>
);
};
I am working with a few APIs that report incidents, I have a collapse component with the titles of each upstream provider. If there's an active incident either based on an incident in the past 24 hours, or if it's in the active section, I would like to make the text in the collapse title red, otherwise make it green.
I created a new state variable called isActive, How would I go about this is React? The first is (App.js file and then Panels.js below.)
import React, { useEffect, useState } from "react";
import { Panels } from "./components/Panels";
import { BrowserRouter as Router, Routes, Route } from
"react-router-dom";
import Navbar from "./components/Navbar";
import "bootstrap/dist/css/bootstrap.min.css";
import "./App.css";
import Home from "./pages/Home";
import Team from "./pages/Team";
import Outages from "./pages/Outages";
function App() {
const emptyFeed = {
title: "",
link: "",
updated: "",
};
const [feed, setFeed] = useState(emptyFeed);
const [feedol, setFeedol] = useState(emptyFeed );
const [jsonData, setJsonData] = useState(emptyFeed);
const [azureData, setAzureData] = useState(emptyFeed);
const [isActive, setIsActive] = useState("false");
const getFeed = () => {
fetch("/feed")
.then((response) => response.json())
.then((data) => {
setFeed(data);
});
};
const getFeedOl = () => {
fetch("/feed_ol")
.then((response) => response.json())
.then((data) => {
setFeedol(data);
});
};
const getJsonData = () => {
fetch("/json_data")
.then((response) => response.json())
.then((data) => {
setJsonData(data["archive"][0]);
});
};
const getAzureData = () => {
fetch("/azure_data")
.then((response) => response.json())
.then((data) => {
setAzureData(data);
});
};
const getAllFour = () => {
getFeed();
getFeedOl();
getJsonData();
getAzureData();
};
useEffect(() => {
getAllFour();
}, []);
return (
<>
<Router>
<Navbar />
<Routes>
<Route exact path="/" element={<Home />} />
<Route path="/team" element={<Team />} />
<Route path="/outages" element={<Outages />} />
</Routes>
</Router>
<Panels
feed={feed}
feedol={feedol}
jsonData={jsonData}
azureData={azureData}
getAllFour={getAllFour}
/>
</>
);
}
export default App;
import React from "react";
import { Collapse } from "antd";
import { Card, Container } from "react-bootstrap";
import { BsArrowClockwise } from "react-icons/bs";
import "./panels.css";
import "antd/dist/antd.css";
const { Panel } = Collapse;
export const Panels = ({ feed, feedol, jsonData,
azureData,
getAllFour }) => {
return (
<Container>
<Card className="table-card">
<Card.Header>
{" "}
<button
type="button"
className=" refresh-button"
onClick={getAllFour}
>
{" "}
<BsArrowClockwise />
</button>{" "}
Upstream Outages{" "}
</Card.Header>
<Collapse accordion>
<Panel header={feedol.title} key="1">
<p>{}</p>
</Panel>
<Panel header={feed.title} key="2">
<p>{}</p>
</Panel>
<Panel header={azureData.title} key="3">
<p>{}</p>
</Panel>
<Panel header={jsonData.service_name} key="4">
<p>{}</p>
</Panel>
</Collapse>
</Card>
</Container>
);
};
Pagination is not working in React Frontend. I am creating an Ecommerce Application and want to Paginate my products on my website. Here is the Code for Getting Product with Pagination.
const getProducts = asyncHandler(async (req, res, next) => {
const pageSize = 3;
const page = Number(req.query.pageNumber) || 1;
const keyword = req.query.keyword
? {
name: {
$regex: req.query.keyword,
$options: 'i',
},
}
: {};
const count = await Product.countDocuments({ ...keyword });
const products = await Product.find({ ...keyword })
.limit(pageSize)
.skip(pageSize * (page - 1))
.sort({ _id: -1 });
res.json({ products, page, pages: Math.ceil(count / pageSize) });
});
I am using Redux for state Management. Here is the code for the Reducer
// PRODUCT LIST
export const productListReducer = (state = { products: [] }, action) => {
switch (action.type) {
case PRODUCT_LIST_REQUEST:
return { loading: true, products: [] };
case PRODUCT_LIST_SUCCESS:
return {
loading: false,
pages: action.payload.pages,
page: action.payload.page,
products: action.payload.products,
};
case PRODUCT_LIST_FAIL:
return { loading: false, error: action.payload };
default:
return state;
}
};
And here is the Action code
// PRODUCT LIST
export const listProduct =
(keyword = ' ', pageNumber = ' ') =>
async (dispatch) => {
try {
dispatch({ type: PRODUCT_LIST_REQUEST });
const { data } = await axios.get(
`/api/products?keyword=${keyword}&pageNumber=${pageNumber}`
);
dispatch({ type: PRODUCT_LIST_SUCCESS, payload: data });
} catch (error) {
dispatch({
type: PRODUCT_LIST_FAIL,
payload:
error.response && error.response.data.error
? error.response.data.error
: error.message,
});
}
};
And this is the Component for pagination and few others
import React, { useEffect } from 'react';
import { Link } from 'react-router-dom';
import Rating from './Rating';
import Pagination from './pagination';
import { useDispatch, useSelector } from 'react-redux';
import { listProduct } from '../../Redux/Actions/ProductActions';
import Loading from '../LoadingError/Loading';
import Message from '../LoadingError/Error';
const ShopSection = (props) => {
const { keyword, pagenumber } = props;
const dispatch = useDispatch();
const productList = useSelector((state) => state.productList);
const { loading, error, products, page, pages } = productList;
useEffect(() => {
dispatch(listProduct(keyword, pagenumber));
}, [dispatch, keyword, pagenumber]);
return (
<>
<div className='container'>
<div className='section'>
<div className='row'>
<div className='col-lg-12 col-md-12 article'>
<div className='shopcontainer row'>
{loading ? (
<div className='mb-5'>
<Loading />
</div>
) : error ? (
<Message variant='alert-danger'>{error}</Message>
) : (
<>
{products.map((product) => (
<div
className='shop col-lg-4 col-md-6 col-sm-6'
key={product._id}
>
<div className='border-product'>
<Link to={`/products/${product._id}`}>
<div className='shopBack'>
<img src={product.image} alt={product.name} />
</div>
</Link>
<div className='shoptext'>
<p>
<Link to={`/products/${product._id}`}>
{product.name}
</Link>
</p>
<Rating
value={product.rating}
text={`${product.numReviews} reviews`}
/>
<h3>${product.price}</h3>
</div>
</div>
</div>
))}
</>
)}
{/* Pagination */}
<Pagination
pages={pages}
page={page}
keyword={keyword ? keyword : ''}
/>
</div>
</div>
</div>
</div>
</div>
</>
);
};
export default ShopSection;
And Pagination Component is here
import React from 'react';
import { Link } from 'react-router-dom';
const Pagination = (props) => {
const { page, pages, keyword = '' } = props;
return (
pages > 1 && (
<nav>
<ul className='pagination justify-content-center'>
{[...Array(pages).keys()].map((x) => (
<li
className={`page-item ${x + 1 === page ? 'active' : ''}`}
key={x + 1}
>
<Link
className='page-link'
to={
keyword
? `/search/${keyword}/page/${x + 1}`
: `/page/${x + 1}`
}
>
{x + 1}
</Link>
</li>
))}
</ul>
</nav>
)
);
};
export default Pagination;
And here is my App.js component
import React from 'react';
import './App.css';
import './responsive.css';
import 'react-toastify/dist/ReactToastify.css';
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
import HomeScreen from './screens/HomeScreen';
import SingleProduct from './screens/SingleProduct';
import Login from './screens/Login';
import Register from './screens/Register';
import CartScreen from './screens/CartScreen';
import ShippingScreen from './screens/ShippingScreen';
import ProfileScreen from './screens/ProfileScreen';
import PaymentScreen from './screens/PaymentScreen';
import PlaceOrderScreen from './screens/PlaceOrderScreen';
import OrderScreen from './screens/OrderScreen';
import NotFound from './screens/NotFound';
import PrivateRouter from './PrivateRoute';
const App = () => {
return (
<Router>
<Switch>
<Route path='/' component={HomeScreen} exact />
<Route path='/search/:keyword' component={HomeScreen} exact />
<Route path='/page/:pagenumber' component={HomeScreen} exact />
<Route
path='/search/:keyword/page/:pageNumber'
component={HomeScreen}
exact
/>
<Route path='/products/:id' component={SingleProduct} />
<Route path='/login' component={Login} />
<Route path='/register' component={Register} />
<PrivateRouter path='/profile' component={ProfileScreen} />
<Route path='/cart/:id?' component={CartScreen} />
<PrivateRouter path='/shipping' component={ShippingScreen} />
<PrivateRouter path='/payment' component={PaymentScreen} />
<PrivateRouter path='/placeorder' component={PlaceOrderScreen} />
<PrivateRouter path='/order/:id' component={OrderScreen} />
<Route path='*' component={NotFound} />
</Switch>
</Router>
);
};
export default App;
When i try to send request from postman the data is returning fine. I have already debug alot and couldn't able to resolve this bug. Help me to resolve this i will be grateful to you
You have to define pagenumber, because it is not defined.
const pagenumber = match.params.pagenumber;
Define it like this.
I hope it will work.
I am new to React, I have JSON data with projects I want to dynamically link. I have created a component called "ProjectSingle" to display each one, however I can't seem to get the data to display.
const App = () => {
const [projects, setProjects] = useState([]);
const getProjects = () => {
fetch('http://localhost:8000/projects')
.then((res) =>{
return res.json();
})
.then((data) => {
setProjects(data);
})
}
useEffect(() => {
getProjects();
AOS.init({disable: 'mobile'});
},[]);
return (
<Router>
<div className="App">
<Switch>
{projects.map( project =>(
<Route exact path='/project/:slug' render={props => (
<ProjectSingle {...props} project={project}/>
)}/>
))}
</Switch>
<Footer/>
</div>
</Router>
);
}
export default App;
The requested JSON is below, I'm using "slug" to generate the slug.
{
"projects": [
{
"title": "Project One",
"image": "/img/wp-logo.png",
"slug": "project-one",
"key": 1
},
{
"title": "Project Two",
"image": "/img/wp-logo.png",
"slug": "project-two",
"key": 2
},
}
Although I'm not sure what data to put in my single component to get the data of the project iteration
const ProjectSingle = ({project}) => {
const { slug } = useParams();
return (
<>
<h1>{project.title}</h1>
</>
)
}
export default ProjectSingle;
Firstly, you only need one <Route path="/project/:slug" /> ... </Route> assigned. The :slug param can be used to dynamically determine what the content of this route will be.
<Route
exact
path="/project/:slug"
render={(props) => <ProjectSingle {...props} projects={projects} />}
/>
const ProjectSingle = ({projects}) => {
const { slug } = useParams();
const project = projects.find(p => p.slug === slug)
return (
<>
<h1>{project.title}</h1>
</>
)
}
export default ProjectSingle;
The route's child (ProjectSingle) will then useParams() to retrieve the value associated with :slug and use that to find the correct project from projects to render.
There may be an even more clever way of using the render() of the route and determining the desired slug & project at that stage - making the ProjectSingle a pure component without any knowledge of routing.
There are several important steps to achive this.
Include libraries like react-router, react-router-dom
Create a history
Render the Route with history
4.Define Navigation to the routes
Here is a sample as per your requirement:
Note: As per your design the routes will render in the same page. I have updated it to be in single file here. complete working example in codesandbox
import React, { useState } from "react";
import { Router, Switch, Route, useParams } from "react-router";
import { Link } from "react-router-dom";
import createHistory from "history/createBrowserHistory";
import "./styles.css";
const history = createHistory();
const Footer = () => {
return <div>Footer here.</div>;
};
const ProjectSingle = ({ project }) => {
const { slug } = useParams();
//TODO useEffect to get project details
return (
<>
<h1>Details of {slug} </h1>
<div>{JSON.stringify(project)}</div>
</>
);
};
export default function App() {
const [projects, setProjects] = useState([
{
title: "Project One",
image: "/img/wp-logo.png",
slug: "project-one",
key: 1
},
{
title: "Project Two",
image: "/img/wp-logo.png",
slug: "project-two",
key: 2
}
]);
/*const getProjects = () => {
fetch('http://localhost:8000/projects')
.then((res) =>{
return res.json();
})
.then((data) => {
setProjects(data);
})
}
useEffect(() => {
getProjects();
AOS.init({disable: 'mobile'});
},[]);
*/
return (
<Router history={history}>
<div className="App">
{projects.map((project) => {
return (
<div key={project.key}>
<Link to={`/project/${project.slug}`}> {project.title} </Link>
</div>
);
})}
<Switch>
{projects.map((project) => (
<Route
key={project.key}
exact
path="/project/:slug"
render={(props) => <ProjectSingle {...props} project={project} />}
/>
))}
</Switch>
<Footer />
</div>
</Router>
);
}
I'm using context and React Router. When I created my context and wrapped my components, nothing rendered. When I check the console, I can see the logged data that I'm fetching (it's coming from useEffect in AnimeContext) but the Header and HomePage components don't appear.
I'm attempting to display topTv, topAiring, and topUpcoming on the HomePage.
Here's the repo
Context file
import React, { useState, useEffect, createContext } from 'react'
const AnimeContext = createContext()
const API = "https://api.jikan.moe/v3"
const AnimeProvider = (props) => {
const urls = [
`${API}/top/anime/1/airing`,
`${API}/top/anime/1/tv`,
`${API}/top/anime/1/upcoming`,
]
// State for top Anime
const [topTv, setTopTv] = useState([])
const [topAiring, setTopAiring] = useState([])
const [topUpcoming, setTopUpcoming] = useState([])
// State for Anime details
const [animeReq, setAnimeReq] = useState({
fetching: false,
anime: []
})
// State for Anime search form
const [dataItems, setDataItems] = useState([])
const [animeSearched, setAnimeSearched] = useState(false)
// Fetch top Anime
const fetchTopAnime = async () => {
return Promise.all(
urls.map(async url => {
return await fetch(url); // fetch data from urls
})
)
.then((responses) => Promise.all(responses.map(resp => resp.json())) // turn data into JSON
.then(data => {
const topTvFiltered = data[0].top.filter(item => item.rank <= 5) // filter out top 6
const topAiringFiltered = data[1].top.filter(item => item.rank <= 5)
const topUpcomingFiltered = data[2].top.filter(item => item.rank <= 5)
setTopTv(topTvFiltered)
setTopAiring(topAiringFiltered)
setTopUpcoming(topUpcomingFiltered)
console.log(data)
})
)
.catch(err => console.log("There was an error:" + err))
}
useEffect(() => {
fetchTopAnime()
}, [])
// Fetch Anime details
const fetchAnimeDetails = async () => {
setAnimeReq({ fetching: true })
const response = await fetch(`${API}/${props.match.params.animeId}`)
const data = await response.json()
console.log(data);
setAnimeReq({ fetching: false, anime: data }) // set initial state to hold data from our API call
}
// Fetch searched Anime
const handleSubmit = async (e) => {
e.preventDefault()
const animeQuery = e.target.elements.anime.value
const response = await fetch(`${API}/search/anime?q=${animeQuery}&page=1`)
// const response2 = await fetch(`${API}/top/anime/1/movie`)
const animeData = await response.json()
// const topAnime = await response2.json()
setDataItems(animeData.results)
setAnimeSearched(!animeSearched)
props.history.push('dashboard')
}
const { fetching, anime } = animeReq;
return (
<AnimeContext.Provider value={{
topTv,
setTopTv,
topAiring,
setTopAiring,
topUpcoming,
setTopUpcoming,
dataItems,
setDataItems,
animeSearched,
setAnimeSearched,
fetching,
anime,
fetchTopAnime,
fetchAnimeDetails,
handleSubmit
}}>
{props.childen}
</AnimeContext.Provider>
)
}
export { AnimeProvider, AnimeContext }
App.js
import React, { Component } from 'react';
import styled, { ThemeProvider } from 'styled-components';
import theme from './config/theme';
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom'
import { AnimeProvider } from './store/AnimeContext'
import Header from './Components/Header';
import HomePage from './Components/Home Page/HomePage';
import AnimeDetails from './Components/AnimeDetails';
import AnimeCard from './Components/AnimeCard/AnimeCard'
class App extends Component {
render() {
return (
<AnimeProvider>
<Router>
<ThemeProvider theme={theme}>
<AppWrapper>
<Header />
<Switch>
<Route path='/' exact component={HomePage} />
<Route path='/dashboard' exact component={AnimeCard} />
<Route path='/:animeId' component={AnimeDetails} />
</Switch>
</AppWrapper>
</ThemeProvider>
</Router>
</AnimeProvider>
);
}
}
const AppWrapper = styled.div`
text-align: center;
font-size: calc(10px + 1vmin);
color: white;
`
export default App;
HomePage Component
import React, { useContext } from 'react'
import styled from 'styled-components'
import { TopAnime } from './TopAnime';
import { AnimeContext } from '../../store/AnimeContext'
const HomePage = () => {
const [topTv, topAiring, topUpcoming,] = useContext(AnimeContext)
return (
<AnimeContext.Consumer>
<HomeWrapper>
<TopAni>
{topTv.length > 0 ? <TopAniTitle>Top TV</TopAniTitle> : null}
{topTv.map((item, index) => (
<TopAnime
key={index}
image={item.image_url}
title={item.title}
item={item}
/>
))}
</TopAni>
<TopAni>
{topAiring.length > 0 ? <TopAniTitle>Top Airing</TopAniTitle> : null}
{topAiring.map((item, index) => (
<TopAnime
key={index}
image={item.image_url}
title={item.title}
item={item}
/>
))}
</TopAni>
<TopAni>
{topUpcoming.length > 0 ? <TopAniTitle>Top Upcoming</TopAniTitle> : null}
{topUpcoming.map((item, index) => (
<TopAnime
key={index}
image={item.image_url}
title={item.title}
item={item}
/>
))}
</TopAni>
</HomeWrapper>
</AnimeContext.Consumer>
);
}
const HomeWrapper = styled.div`
height: 100%;
padding: 6rem 4.5rem;
color: ${props => props.theme.colors.white};
`
const TopAni = styled.div`
max-width: 1200px;
margin: 0 auto;
display: grid;
grid-gap: 1rem;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
grid-template-rows: auto;
padding: 1rem;
`
const TopAniTitle = styled.h2`
grid-column: 1 / -1;
justify-self: start;
`
export default HomePage
If I move my AnimeProvider below the Header, I am able to view the header like so:
return (
<Router>
<ThemeProvider theme={theme}>
<AppWrapper>
<Header />
<Switch>
<AnimeProvider>
<Route path='/' exact component={HomePage} />
<Route path='/dashboard' exact component={AnimeCard} />
<Route path='/:animeId' component={AnimeDetails} />
</AnimeProvider>
</Switch>
</AppWrapper>
</ThemeProvider>
</Router>
);
So I'm either missing something crucial or I'm not understanding how Context works and/or React Router.
You have a typo in AnimeProvider - it should render {props.children} not {props.childen}
AnimeContext.Consumer requires a function as a child, also if you are using useContext then there is no need to wrap your component with AnimeContext.Consumer in first place.
Also since your provider pass down an object, then useContext would return an object, so you need object destructuring instead of array destructuring.
const HomePage = () => {
const { topTv, topAiring, topUpcoming } = useContext(AnimeContext)
return (
<HomeWrapper>
<TopAni>
{topTv.length > 0 ? <TopAniTitle>Top TV</TopAniTitle> : null}
{topTv.map((item, index) => (
<TopAnime
key={index}
image={item.image_url}
title={item.title}
item={item}
/>
))}
</TopAni>
...
</HomeWrapper>
}
}