开发者问题收集

React Redux,我的组件未连接到 Redux Store。我在另一个组件中测试了操作和 Reducer,它对其他组件有效吗?

2019-05-09
177

流程如下:

  1. 点击 CarouselItem ,触发 onClick={this.handleId

  2. handleId 接受 id,它是被点击的 CarouselItem 的一个 prop>

  3. this.props.dispatch(fetchRecon(movieId)); 将执行 AJAX 操作,该操作将返回数据

  4. 并在 Redux 状态中,将最初为 moviesRecon:[] 的属性设置为 moviesRecon:[data]handleId 还会使用 this.props.history.push(`/movie-detail?query=${movieId}`);

  5. 将我路由到新页面
  6. 我现在应该位于组件 MovieDetailPage 上,该组件当前正在使用 Carousel 组件的模拟数据。理想情况下,我应该为 Carousel 的电影 prop 传递 this.props.movi​​esRecon

尝试这样做会给我以下错误:

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 正确设置了状态,因为其他组件能够访问电影侦察。

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
        });
    }
}
3个回答

您因此行而收到错误,

 <Carousel title={"Recommended"} movies={recommended} />

您正在传递一个组件 recommended ,我可以看到在您的情况下使用 import { Recommended } from './mock'; 导入了该组件。

Carousel 组件中,您尝试使用 map 遍历 movies 数组。

这就是您收到错误的原因,因为 recommended 是一个 component 而不是 不是 array

尝试将 array 传递给所有子组件。

ravibagul91
2019-05-09

我认为您在组件有足够的时间获取电影数据之前就启动了 .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>
    )
  }
}

顺便说一句,您似乎正在尝试将 settings 对象扩展到 Slider 组件中,但您从未定义过设置。应该调查一下。

Cat_Enthusiast
2019-05-09

好的,我搞明白了。基本上,我在更高级别的 App.js 组件中写错了导入,这就是它无法连接的原因。我试图导入 MovieDetailPage 的一个名为 MovieDetailPage 的成员,而不是默认导出,这是我需要的连接组件。所以是打字错误...

我有 { MovieDetailPage },它应该是 MovieDetailPage

Kaleidics
2019-05-09