我正在使用上下文和React Router。当我创建上下文并包装组件时,什么也没有呈现。当我检查控制台时,可以看到我正在获取的记录数据(来自AnimeContext
中的useEffect),但是没有出现Header和HomePage组件。
我正在尝试在topTv
上显示topAiring
,topUpcoming
和HomePage
。
这里是repo
上下文文件
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;
主页组件
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
如果将AnimeProvider
移到Header
下方,则可以这样查看标题:
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>
);
所以我要么错过了一些关键的东西,要么不了解Context的工作方式和/或React Router。
答案 0 :(得分:1)
您在AnimeProvider
中有一个错字-它应该呈现{props.children}
而不是{props.childen}
答案 1 :(得分:0)
AnimeContext.Consumer
作为孩子需要一个函数,同样,如果您使用的是useContext
,则无需首先用AnimeContext.Consumer
包装组件
另外,由于您的提供者传递了一个对象,因此useContext
将返回一个对象,因此您需要对象分解而不是数组分解。
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>
}
}