简体   繁体   English

React Redux,我的组件未连接到Redux Store。 我在另一个组件中测试了动作和减速器,它是否对其他组件有效?

[英]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?

The flow is like this: 流程是这样的:

  1. Click on CarouselItem , which trigger the onClick={this.handleId} . 单击CarouselItem ,这会触发onClick={this.handleId}

  2. handleId takes the id, which is a prop of the clicked CarouselItem handleId采用ID,该ID是单击的CarouselItem

  3. this.props.dispatch(fetchRecon(movieId)); will make an AJAX action, which will return data 将执行AJAX操作,该操作将返回数据

  4. and within the Redux state, set a property that initially is moviesRecon:[] to moviesRecon:[data] . 并在Redux状态中,将最初为moviesRecon:[]的属性设置为moviesRecon:[data] handleId will also route me to a new page using this.props.history.push(`/movie-detail?query=${movieId}`); handleId还将使用this.props.history.push(`/movie-detail?query=${movieId}`);将我路由到新页面this.props.history.push(`/movie-detail?query=${movieId}`);

  5. I should now be on the component MovieDetailPage , which is currently using mock data for the Carousel component. 我现在应该在组件MovieDetailPage ,该组件当前正在为Carousel组件使用模拟数据。 Ideally, I should be passing this.props.moviesRecon for the movies prop of Carousel . 理想情况下,我应该将this.props.moviesRecon传递给Carousel的电影道具。

Attempting to do so gives me the following error: 尝试这样做会给我以下错误:

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 |         );

Here are the components that I think are relevant: CarouselItem.js 以下是我认为相关的组件: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 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 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));

For MovieDetailPage.js on line 29 I am logging the following in the console: 对于第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, if necessary, but I have already confirmed the action, and reducer are correctly setting the state, as other components are able to access moviesRecon. Reducers.js,如有必要,但我已经确认了该操作,并且reducer正确设置了状态,因为其他组件也可以访问movieRecon。

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
        });
    }
}

You are getting error due to this line, 由于此行,您收到了错误消息,

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

You are passing a component recommended , which I can see is imported in your case, using import { recommended } from './mock'; 您正在传递一个recommended用组件,我可以看到它是在您的情况下使用import { recommended } from './mock'; .

In the Carousel component you are trying to iterate over the movies array using map . Carousel组件,您正试图遍历movies使用数组map

This is why you are getting error, because recommended is a component and not a array . 这就是为什么会出错的原因,因为recommendedcomponent不是 array

Try to pass array to all your child component's. 尝试将array传递给所有子组件。

I think you initiate your .map before your component has enough time to obtain the movies data. 我认为您应该在组件有足够的时间获取影片数据之前启动.map You can do the following to check for that: 您可以执行以下操作进行检查:

Carousel.js 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>
    )
  }
}

On a side-note, it looks like you're trying to spread the settings object into your Slider component, but you never defined settings anyway. 在旁注中,您似乎正在尝试将settings对象散布到Slider组件中,但是无论如何您从未定义设置。 Should look into that. 应该调查一下。

Ok so I figured it out. 好的,所以我知道了。 I basically wrote my import wrong in my higher level App.js component, that's why it wasn't being connected. 我基本上在更高级别的App.js组件中输入了导入错误,这就是为什么它没有连接的原因。 I was attempting to import a member of the MovieDetailPage named MovieDetailPage and not the default export, which was the connected component I needed. 我试图导入名为MovieDetailPage的MovieDetailPage的成员,而不是默认导出,这是我需要的已连接组件。 So a typo... 错字了...

I had { MovieDetailPage } and it should be MovieDetailPage 我有{ MovieDetailPage } ,应该是MovieDetailPage

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM