在我的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;
}
答案 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
}
}