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

Posted

技术标签:

【中文标题】Redux 状态道具未定义且 ComponentDidMount 未触发【英文标题】:Redux state props undefined and ComponentDidMount not firing 【发布时间】:2018-09-20 17:08:27 【问题描述】:

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

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

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

现在,电影页面呈现空白,因为控制台返回 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 减速器

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 减速器

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 存储

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】:

这是您的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
  

【讨论】:

以上是关于Redux 状态道具未定义且 ComponentDidMount 未触发的主要内容,如果未能解决你的问题,请参考以下文章

Redux 状态未在开发工具中更新,但当前状态正在反映在道具中

React Redux TypeError:无法读取未定义的属性“地图”

反应自定义组件 - 无法根据道具设置状态

REACT + REDUX:在 redux 状态更改时 mapStateToProps 更新状态,但视图未按照新状态呈现

React Redux:为啥这个嵌套组件没有从 redux 状态接收道具?

关于未找到状态且不可分配给类型的 next-redux-wrapper 的 Typescript 警告