React Redux,我的组件没有连接到 Redux Store。我在另一个组件中测试了 action 和 reducer,它对其他组件有效吗?
React Redux, my component is not connected to Redux Store. I tested the action and reducer in another component, it does work for other components?
流程是这样的:
单击 CarouselItem
,这会触发 onClick={this.handleId}
。
handleId
取id,是被点击的prop CarouselItem
this.props.dispatch(fetchRecon(movieId));
将执行 AJAX 操作,这将 return 数据
并在 Redux 状态中,将最初为 moviesRecon:[]
的 属性 设置为 moviesRecon:[data]
。 handleId
还将使用 this.props.history.push(`/movie-detail?query=${movieId}`);
将我引导至新页面
我现在应该在组件 MovieDetailPage
上,该组件当前正在为 Carousel
组件使用模拟数据。理想情况下,我应该为 Carousel
的电影道具传递 this.props.moviesRecon
。
尝试这样做会出现以下错误:
TypeError: Cannot read property 'map' of undefined
const carousel = this.props.movies.map((item, index) => {
| ^ 51 | return (
52 | <CarouselItem data={item} index={index} key={this.props.movies[index].id} id={this.props.movies[index].id} />
53 | );
以下是我认为相关的组件:
CarouselItem.js
import React from 'react';
import './CarouselItem.css';
import { connect } from 'react-redux';
import { Link } from 'react-router-dom';
import { fetchRecon } from '../../actions/index';
import { withRouter } from 'react-router-dom';
export class CarouselItem extends React.Component{
handleId = e => {
let movieId = this.props.id
console.log("carousel item", movieId);
this.props.dispatch(fetchRecon(movieId));
this.props.history.push(`/movie-detail?query=${movieId}`);
}
render() {
let genres = this.props.genres;
let genreList = this.props.genres.length;
function getGenreText(id) {
for (let i = 0; i < genreList; i++) {
if (genres[i].id == id) {
return genres[i].name;
}
}
}
if (this.props.data) {
return (
<div className="movieContainer" onClick={this.handleId}>
<img className="moviePoster" src={`https://image.tmdb.org/t/p/w500/${this.props.data.poster_path}`} alt={this.props.data.title} />
<h3 className="movieName">{this.props.data.title}</h3>
<p className="movieGenre">{getGenreText(this.props.data.genre_ids[0])}</p>
</div>
);
}
}
}
const mapStateToProps = state => ({
genres: state.app.genres
});
export default connect(mapStateToProps)(withRouter(CarouselItem));
Carousel.js
import React from 'react';
import CarouselItem from '../CarouselItem/CarouselItem';
import './Carousel.css';
import Slider from "react-slick";
import "slick-carousel/slick/slick.css";
import "slick-carousel/slick/slick-theme.css";
export class Carousel extends React.Component {
componentDidMount() {
// the trick
setTimeout(() => {
this.forceUpdate();
}, 50);
}
render(){
console.log("carousel probs", this.props);
const carousel = this.props.movies.map((item, index) => {
return (
<CarouselItem data={item} index={index} key={this.props.movies[index].id} id={this.props.movies[index].id} />
);
});
return (
<div className="inner-carousel">
<h2>{this.props.title}</h2>
<Slider {...settings}>
{carousel}
</Slider>
<hr className="carousel-divider"/>
</div>
)
}
}
MovieDetailPage.js
import React from 'react';
import { connect } from 'react-redux';
import { Carousel } from '../Carousel/Carousel';
import { withRouter } from 'react-router-dom';
import {fetchRecon} from '../../actions/index';
import { recommended } from './mock';
import { movieDetails } from './mockdetails';
import './MovieDetailPage.css';
export class MovieDetailPage extends React.Component {
componentDidMount() {
window.scrollTo(0, 0);
window.onpopstate = () => {
const params = (new URL(document.location)).searchParams;
const clickedMovie = params.get("query");
console.log('here', clickedMovie);
}
const params = (new URL(document.location)).searchParams;
const movieId = params.get("query");
console.log('here', movieId);
// this.props.dispatch(fetchRecon(movieId));
}
render() {
console.log('movie detail', this.props.moviesRecon, this.props)
return (
<div className="movieDetail">
<div className="movieDetail-container">
<img className="movieDetail-bg" src={`https://image.tmdb.org/t/p/original/or06FN3Dka5tukK1e9sl16pB3iy.jpg`} />
</div>
<div className="main-details">
<Carousel title={"Recommended"} movies={recommended} />
<Carousel title={"Recommended"} movies={recommended} />
<Carousel title={"Recommended"} movies={recommended} />
<Carousel title={"Recommended"} movies={recommended} />
<Carousel title={"Recommended"} movies={recommended} />
<Carousel title={"Recommended"} movies={recommended} />
<Carousel title={"Recommended"} movies={this.props.moviesRecon} />
</div>
</div>
);
}
}
const mapStateToProps = state => ({
isLoading: state.app.isLoading,
moviesRecon: state.app.moviesRecon
});
export default connect(mapStateToProps)(withRouter(MovieDetailPage));
对于第 29 行的 MovieDetailPage.js,我在控制台中记录了以下内容:
movie detail undefined
{history: {…}, location: {…}, match: {…}, staticContext: undefined}
history: {length: 17, action: "PUSH", location: {…}, createHref: ƒ, push: ƒ, …}
location: {pathname: "/movie-detail", search: "?query=456740", hash: "", state: undefined, key: "dyth5r"}
match: {path: "/movie-detail", url: "/movie-detail", isExact: true, params: {…}}
staticContext: undefined
__proto__: Object
Reducers.js,如果有必要,但我已经确认了动作,reducer 正在正确设置状态,因为其他组件能够访问 moviesRecon。
const initialState = {
isLoading: 0,
genres: [],
moviesPlaying: [],
moviesPopular: [],
moviesUpcoming: [],
moviesTop: [],
movieSearch:[],
moviesRecon: [],
searchTerm: ""
};
export const Reducer = (state=initialState, action) => {
if (action.type === FETCH_RECON_SUCCESS) {
return Object.assign({}, state, {
moviesRecon: action.recon
});
}
}
由于这一行,您收到错误消息,
<Carousel title={"Recommended"} movies={recommended} />
您正在传递一个组件 recommended
,我可以看到它是在您的案例中使用 import { recommended } from './mock';
导入的。
在 Carousel
组件中,您尝试使用 map
.
遍历 movies
数组
这就是您出错的原因,因为 recommended
是 component
而 不是 array
.
尝试将 array
传递给所有子组件。
我认为您在组件有足够时间获取电影数据之前启动了 .map
。您可以执行以下操作来检查:
Carousel.js
import React from 'react'
import CarouselItem from '../CarouselItem/CarouselItem'
import './Carousel.css'
import Slider from 'react-slick'
import 'slick-carousel/slick/slick.css'
import 'slick-carousel/slick/slick-theme.css'
export class Carousel extends React.Component {
componentDidMount() {
// the trick
setTimeout(() => {
this.forceUpdate()
}, 50)
}
createCarousels = () => {
const movies = this.props.movies
if (movies.length > 0) {
return movies.map((item, index) => {
return (
<CarouselItem
data={item}
index={index}
key={this.props.movies[index].id}
id={this.props.movies[index].id}
/>
)
})
}
}
render() {
return (
<div className="inner-carousel">
<h2>{this.props.title}</h2>
<Slider {...settings}>{this.createCarousels()}</Slider>
<hr className="carousel-divider" />
</div>
)
}
}
在 side-note 上,您似乎试图将 settings
对象散布到 Slider
组件中,但您从未定义设置。应该调查一下。
好的,我明白了。我基本上在更高级别的 App.js 组件中写错了我的导入,这就是它没有被连接的原因。我试图导入名为 MovieDetailPage 的 MovieDetailPage 成员,而不是默认导出,这是我需要的连接组件。所以打错了...
我有 { MovieDetailPage }
应该是 MovieDetailPage
流程是这样的:
单击
CarouselItem
,这会触发onClick={this.handleId}
。handleId
取id,是被点击的propCarouselItem
this.props.dispatch(fetchRecon(movieId));
将执行 AJAX 操作,这将 return 数据并在 Redux 状态中,将最初为
moviesRecon:[]
的 属性 设置为moviesRecon:[data]
。handleId
还将使用this.props.history.push(`/movie-detail?query=${movieId}`);
将我引导至新页面
我现在应该在组件
MovieDetailPage
上,该组件当前正在为Carousel
组件使用模拟数据。理想情况下,我应该为Carousel
的电影道具传递this.props.moviesRecon
。
尝试这样做会出现以下错误:
TypeError: Cannot read property 'map' of undefined
const carousel = this.props.movies.map((item, index) => {
| ^ 51 | return (
52 | <CarouselItem data={item} index={index} key={this.props.movies[index].id} id={this.props.movies[index].id} />
53 | );
以下是我认为相关的组件: CarouselItem.js
import React from 'react';
import './CarouselItem.css';
import { connect } from 'react-redux';
import { Link } from 'react-router-dom';
import { fetchRecon } from '../../actions/index';
import { withRouter } from 'react-router-dom';
export class CarouselItem extends React.Component{
handleId = e => {
let movieId = this.props.id
console.log("carousel item", movieId);
this.props.dispatch(fetchRecon(movieId));
this.props.history.push(`/movie-detail?query=${movieId}`);
}
render() {
let genres = this.props.genres;
let genreList = this.props.genres.length;
function getGenreText(id) {
for (let i = 0; i < genreList; i++) {
if (genres[i].id == id) {
return genres[i].name;
}
}
}
if (this.props.data) {
return (
<div className="movieContainer" onClick={this.handleId}>
<img className="moviePoster" src={`https://image.tmdb.org/t/p/w500/${this.props.data.poster_path}`} alt={this.props.data.title} />
<h3 className="movieName">{this.props.data.title}</h3>
<p className="movieGenre">{getGenreText(this.props.data.genre_ids[0])}</p>
</div>
);
}
}
}
const mapStateToProps = state => ({
genres: state.app.genres
});
export default connect(mapStateToProps)(withRouter(CarouselItem));
Carousel.js
import React from 'react';
import CarouselItem from '../CarouselItem/CarouselItem';
import './Carousel.css';
import Slider from "react-slick";
import "slick-carousel/slick/slick.css";
import "slick-carousel/slick/slick-theme.css";
export class Carousel extends React.Component {
componentDidMount() {
// the trick
setTimeout(() => {
this.forceUpdate();
}, 50);
}
render(){
console.log("carousel probs", this.props);
const carousel = this.props.movies.map((item, index) => {
return (
<CarouselItem data={item} index={index} key={this.props.movies[index].id} id={this.props.movies[index].id} />
);
});
return (
<div className="inner-carousel">
<h2>{this.props.title}</h2>
<Slider {...settings}>
{carousel}
</Slider>
<hr className="carousel-divider"/>
</div>
)
}
}
MovieDetailPage.js
import React from 'react';
import { connect } from 'react-redux';
import { Carousel } from '../Carousel/Carousel';
import { withRouter } from 'react-router-dom';
import {fetchRecon} from '../../actions/index';
import { recommended } from './mock';
import { movieDetails } from './mockdetails';
import './MovieDetailPage.css';
export class MovieDetailPage extends React.Component {
componentDidMount() {
window.scrollTo(0, 0);
window.onpopstate = () => {
const params = (new URL(document.location)).searchParams;
const clickedMovie = params.get("query");
console.log('here', clickedMovie);
}
const params = (new URL(document.location)).searchParams;
const movieId = params.get("query");
console.log('here', movieId);
// this.props.dispatch(fetchRecon(movieId));
}
render() {
console.log('movie detail', this.props.moviesRecon, this.props)
return (
<div className="movieDetail">
<div className="movieDetail-container">
<img className="movieDetail-bg" src={`https://image.tmdb.org/t/p/original/or06FN3Dka5tukK1e9sl16pB3iy.jpg`} />
</div>
<div className="main-details">
<Carousel title={"Recommended"} movies={recommended} />
<Carousel title={"Recommended"} movies={recommended} />
<Carousel title={"Recommended"} movies={recommended} />
<Carousel title={"Recommended"} movies={recommended} />
<Carousel title={"Recommended"} movies={recommended} />
<Carousel title={"Recommended"} movies={recommended} />
<Carousel title={"Recommended"} movies={this.props.moviesRecon} />
</div>
</div>
);
}
}
const mapStateToProps = state => ({
isLoading: state.app.isLoading,
moviesRecon: state.app.moviesRecon
});
export default connect(mapStateToProps)(withRouter(MovieDetailPage));
对于第 29 行的 MovieDetailPage.js,我在控制台中记录了以下内容:
movie detail undefined
{history: {…}, location: {…}, match: {…}, staticContext: undefined}
history: {length: 17, action: "PUSH", location: {…}, createHref: ƒ, push: ƒ, …}
location: {pathname: "/movie-detail", search: "?query=456740", hash: "", state: undefined, key: "dyth5r"}
match: {path: "/movie-detail", url: "/movie-detail", isExact: true, params: {…}}
staticContext: undefined
__proto__: Object
Reducers.js,如果有必要,但我已经确认了动作,reducer 正在正确设置状态,因为其他组件能够访问 moviesRecon。
const initialState = {
isLoading: 0,
genres: [],
moviesPlaying: [],
moviesPopular: [],
moviesUpcoming: [],
moviesTop: [],
movieSearch:[],
moviesRecon: [],
searchTerm: ""
};
export const Reducer = (state=initialState, action) => {
if (action.type === FETCH_RECON_SUCCESS) {
return Object.assign({}, state, {
moviesRecon: action.recon
});
}
}
由于这一行,您收到错误消息,
<Carousel title={"Recommended"} movies={recommended} />
您正在传递一个组件 recommended
,我可以看到它是在您的案例中使用 import { recommended } from './mock';
导入的。
在 Carousel
组件中,您尝试使用 map
.
movies
数组
这就是您出错的原因,因为 recommended
是 component
而 不是 array
.
尝试将 array
传递给所有子组件。
我认为您在组件有足够时间获取电影数据之前启动了 .map
。您可以执行以下操作来检查:
Carousel.js
import React from 'react'
import CarouselItem from '../CarouselItem/CarouselItem'
import './Carousel.css'
import Slider from 'react-slick'
import 'slick-carousel/slick/slick.css'
import 'slick-carousel/slick/slick-theme.css'
export class Carousel extends React.Component {
componentDidMount() {
// the trick
setTimeout(() => {
this.forceUpdate()
}, 50)
}
createCarousels = () => {
const movies = this.props.movies
if (movies.length > 0) {
return movies.map((item, index) => {
return (
<CarouselItem
data={item}
index={index}
key={this.props.movies[index].id}
id={this.props.movies[index].id}
/>
)
})
}
}
render() {
return (
<div className="inner-carousel">
<h2>{this.props.title}</h2>
<Slider {...settings}>{this.createCarousels()}</Slider>
<hr className="carousel-divider" />
</div>
)
}
}
在 side-note 上,您似乎试图将 settings
对象散布到 Slider
组件中,但您从未定义设置。应该调查一下。
好的,我明白了。我基本上在更高级别的 App.js 组件中写错了我的导入,这就是它没有被连接的原因。我试图导入名为 MovieDetailPage 的 MovieDetailPage 成员,而不是默认导出,这是我需要的连接组件。所以打错了...
我有 { MovieDetailPage }
应该是 MovieDetailPage