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?

Related searches

The flow is like this:

  1. Click on CarouselItem, which trigger the onClick={this.handleId}.

  2. handleId takes the id, which is a prop of the clicked CarouselItem

  3. this.props.dispatch(fetchRecon(movieId)); will make an AJAX action, which will return data

  4. and within the Redux state, set a property that initially is moviesRecon:[] to moviesRecon:[data]. handleId will also route me to a new page using 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. Ideally, I should be passing this.props.moviesRecon for the movies prop of 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

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

For MovieDetailPage.js on line 29 I am logging the following in the console:

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.

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';.

In the Carousel component you are trying to iterate over the movies array using map.

This is why you are getting error, because recommended is a component and not a array.

Try to pass array to all your child component's.

Troubleshooting, Sometimes, you are trying to dispatch an action, but your view does not assumes that you never mutate the objects it gives to you in the reducer. lets react-redux efficiently subscribe to fine-grained updates of your state. Won't work! This is why react-redux lets you use a connect higher-order component that will,� React + Redux – Component not exported or Redux not connected Posted on May 9, 2019 by lysender Hey there, I’m a React and Redux newbie and the annoying issue I’ve encountered is when you connect a component to Redux but the actions are not injected into the component’s props.

I think you initiate your .map before your component has enough time to obtain the movies data. You can do the following to check for that:

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. Should look into that.

Usage with React, React bindings for Redux separate presentational components from container components. To change data, Invoke callbacks from props, Dispatch Redux actions to generate a few container components to connect them to the Redux store. If a container component becomes too complex (i.e. it has heavily nested � The connect function generates a wrapper component that subscribes to the store. When an action is dispatched, the wrapper component's callback is notified. It then runs your mapState function, and shallow-compares the result object from this time vs the result object from last time (so if you were to rewrite a redux store field with its same value, it would not trigger a re-render).

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. I was attempting to import a member of the MovieDetailPage named MovieDetailPage and not the default export, which was the connected component I needed. So a typo...

I had { MovieDetailPage } and it should be MovieDetailPage

React Redux, Why don't I have this.props.dispatch available in my connected component? far the most common reason why components do not re-render after an action has been Redux expects that your reducers will update their state “immutably”, which is a different reference, so the shallow equality check fails and React Redux� Our component has also a button element which dispatches an action to our Redux store. We call this action myAction(payload) whereas `payload can be any parameters passed to that action. In conclusion, our React component is connected both ways to the Redux store: it receives state (e.g. via mapStateToProps) and dispatches an action (e.g. via

Deciding When to Connect Your Component to the Redux Store , Redux is my go-to state management tool, when building a web app for scaling. Regardless of the hassle one has to go through initially, with a large Redux is the task of connecting your components to the Redux store and actions . component and initialize the store, actions, and reducer for Redux. The React Redux connect function works great for regular React components, but if you need access to the Redux store in a plain function, the technique is a bit different. In the examples below I’ll show how to access a JWT token from the Redux store, but the techniques will work with any data you might have.

How to test React-Redux connected Components, React components connected to Redux can turn out pretty complex. However, it's up to you to extend your testing setup with React Testing Library or Redux State -> React Component -> Redux Action should ensure that all actions/ reducers/sagas within the actual Redux store work as expected. Testing React+Redux with Jest+Enzyme. When I did my previous post, I purposefully left out how to test connected components. With components that are connected to a Redux store, it takes a little bit more effort to set up test files and write tests. For this example I am using Jest and Enzyme to do my testing.

It doesn't work because your action creator is just a function that returns an action. It is up to you to actually dispatch it. It is up to you to actually dispatch it. We can't bind your action creators to a particular Store instance during the definition because apps that render on the server need a separate Redux store for every request.

Comments
  • Just wrote you an answer friend! Let me know if that helps you out.
  • It's unclear whether it's actually a component though. recommended could very likely be an array.
  • @ChristopherNgo Try to comment all other child component which are using recommended and see if your code works.
  • Oh my mistake for not clarifying, the component recommended is mock data, which I am using to see if the component is failing because of the component itself. Which it is not. It is movies={this.props.moviesRecon} that is failing. And that is because I believe the component is not connected to the Redux Store for some reason.
  • @Kaleidics But what is the mock data. Is it an array []. Or an object {}? Or an actual component?
  • The mock data is an array of objects. Commenting out movies={this.props.moviesRecon}, and the application will run using the mock data and I will have 5 Carousels displayed on the dom. However, commenting out the Carousel with mock data, and leaving in movies={this.props.moviesRecon} and the app will crash.
  • I did not include the settings for readability reasons. But I just tried your solution and I got TypeError: Cannot read property 'length' of undefined if (movies.length > 0) { Which comes back to the same problem, it doesn't look like MovieDetailPage.js is getting the Redux Store. And, therefore when it passes it as props to carousel. this.props is being undefined.