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?

流程是这样的:

  1. 单击 CarouselItem,这会触发 onClick={this.handleId}

  2. handleId取id,是被点击的prop CarouselItem

  3. this.props.dispatch(fetchRecon(movieId)); 将执行 AJAX 操作,这将 return 数据

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

  5. 将我引导至新页面
  6. 我现在应该在组件 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 数组

这就是您出错的原因,因为 recommendedcomponent 不是 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