Redux状态道具未定义且ComponentDidMount未触发

时间:2018-04-11 00:04:51

标签: node.js reactjs redux react-redux

在我的localhost react-node应用程序中,当我点击Movies.js页面时,应用程序将对{localhost}/api/movies节点端点进行api调用(我正在使用redux-thunk中间件btw) 。

然后它将json返回this.props.movies.displayedMovies(入口点为componentDidMount()),然后将其传递给render()

从那时起,唯一的变化是我添加了另一个reducer MusicReducer并使用redux的combinedReducer(..)来配置存储。

现在,电影页面呈现空白,因为控制台正在返回Cannot read property 'displayedMovies' of undefined并且似​​乎没有调用componentDidMount。

不确定问题是什么。下面是代码。任何帮助,将不胜感激。

Movies.js容器

import React, { Component } from 'react'
import ReactDOM from 'react-dom'
import { BrowserRouter as Router, Route } from 'react-router-dom'

import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import * as moviesActions from '../actions/MoviesActions'

import NavBar from '../components/NavBar'
import ResultsBar from '../components/ResultsBar'
import Grid from '../components/Grid'
import * as utils from '../utils/utils.js'
import style from '../style/App.css'

class Movies extends Component {

  handleSearch(e) {
    this.props.moviesActions.filterMovies(e.target.value)
  }

  componentDidMount() {
    this.props.moviesActions.fetchMovies()
  }

  render() {
    let { displayedMovies } = this.props.movies

    return (
      <div>
      <NavBar onChange={this.handleSearch.bind(this)} type={0}/>
      <br/>
      <ResultsBar count={displayedMovies.length} type={0}/>
      <Grid
          gridData={JSON.stringify(displayedMovies)}
          gridCell_width={140}
          gridCell_height={200}
          type={0}
      />
      </div>
    );
  }
}

function mapStateToProps(state) {
  return {
    movies: state.movies
  }
}

function mapDispatchToProps(dispatch) {
  return {
    moviesActions: bindActionCreators(moviesActions, dispatch)
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(Movies)

MoviesActions.js动作

import {
  REQUEST_MOVIES,
  RECEIVE_MOVIES,
  FILTER_MOVIES,
  SORT_MOVIES
} from '../constants/Page'
import * as utils from '../utils/utils.js'

function requestMovies() {
  return {
    type: REQUEST_MOVIES
  }
}

function receiveMovies(json) {
  return {
    type: RECEIVE_MOVIES,
    movies: json
  }
}

export function fetchMovies() {

  return dispatch => {
    dispatch(requestMovies())

    utils.callApi('/api/movies')
      .then(items => {
        var data = [];
        for (var i = 0; i < items.length; i++) {
          data.push({
            tmdb_id: items[i].id, 
            imdb_id: items[i].imdb_id, 
            title: items[i].title, 
            poster_path: 'https://image.tmdb.org/t/p/w500' + items[i].poster_path,
            backdrop_path: 'https://image.tmdb.org/t/p/original' + items[i].backdrop_path, 
            url_path: items[i].url_path, 
            release_date: items[i].release_date, 
            runtime: items[i].runtime, 
            revenue: items[i].revenue,
            overview: items[i].overview,
            tagline: items[i].tagline, 
            link: 'http://www.imdb.com/title/' + items[i].imdb_id
          });
        }
        dispatch(receiveMovies(data))
      })
      .catch(err => console.log(err));
  }

}

export function filterMovies(searchTerm) {
  return {
    type: FILTER_MOVIES,
    searchTerm
  }
}

export function sortMovies(sortOption) {
  return {
    type: SORT_MOVIES,
    sortOption
  }
}

index.js reducer

import { combineReducers } from 'redux'
import {
  BOOKS,
  COMICS,
  MOVIES,
  MUSIC,
  PODCASTS,
  TV
} from '../constants/Page'
import moviesReducer from './MoviesReducer'
import musicReducer from './MusicReducer'

export default combineReducers({
  moviesReducer,
  musicReducer
})

MoviesReducer.js reducer

import {
  REQUEST_MOVIES,
  RECEIVE_MOVIES,
  FILTER_MOVIES,
  SORT_MOVIES
} from '../constants/Page'

const initialState = {
  movies: [],
  displayedMovies: []
}

export default function movie(state = initialState, action) {
  switch (action.type) {
    case REQUEST_MOVIES:
      return {
        ...state
      }

    case RECEIVE_MOVIES:
      let movies = action.movies
      return {
        ...state,
        movies,
        displayedMovies: movies
      }

    case FILTER_MOVIES:
      let displayedMovies = state.movies.filter(movie => {
        if (movie.title.toLowerCase().includes(action.searchTerm.toLowerCase())) {
          return true
        }
        return false
      })
      return {
        ...state,
        displayedMovies,
        displayedMovies: displayedMovies
      }

    case SORT_MOVIES:
      let sortDisplayedMovies
      switch(action.sortOption) {
        case 'Alphabetical':
          sortDisplayedMovies = state.displayedMovies.sort((a,b)=> {
            var a1 = a.title.toLowerCase();
            var b1 = b.title.toLowerCase();
            return a1<b1 ?-1:a1> b1? 1 :0;
          })
          break;
        case 'Oldest':
          sortDisplayedMovies = state.displayedMovies.sort((a,b)=> {
            return new Date(a.release_date).getTime() - new Date(b.release_date).getTime();
          })
          break;
        case 'Newest':
          sortDisplayedMovies = state.displayedMovies.sort((a,b)=> {
            return new Date(b.release_date).getTime() - new Date(a.release_date).getTime();
          })
          break;
        default:
          break;
      }
      return {
        ...state,
        sortDisplayedMovies,
        displayedMovies: sortDisplayedMovies
      }

    default:
      return state
  }

}

configureStore.js store

import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from '../reducers/index'

export default function configureStore() {
  const store = createStore(
    rootReducer, 
    applyMiddleware(thunk)
  );

  return store;
}

1 个答案:

答案 0 :(得分:1)

这是mapStateToProps的问题。

因为您已将combineReducers定义如下

export default combineReducers({
  moviesReducer,
  musicReducer
})

与以下相同

export default combineReducers({
  movieReducer:movieReducer,
  musicReducer:musicReducer
})

你的电影状态在

之内
state.movieReducer.movies

这意味着你的mapStateToProps必须像这样注入正确的值

function mapStateToProps(state) {
  return {
    movies: state.movieReducer.movies
  }
}