2016-07-31 14 views
1

Ich bin neu in React and Redux und bin immer noch ein bisschen verwirrt.TypeError: Kann die Eigenschaft 'map' von undefined in react-redux nicht lesen

Mein Ziel ist es, eine Menge von JSON-Daten im HTML mit GET-Anfrage zu rendern. Ich benutze reagieren und redux, um den Zustand der Objekte zu verwalten, aber ich glaube mein Problem ist, dass die Daten nicht einmal dort

so im Grunde immer wenn jemand eine URL/Kurse anfordern, er/sie wird eine Menge Daten sehen in json.

ich den Fehler in der Komponente erhalten

TypeError: Cannot read property 'map' of undefined

Hier ist der Code

Aktion

export function getCourses() { 
    return (dispatch) => { 

    return fetch('/courses', { 
     method: 'get', 
     headers: { 'Content-Type', 'application/json' }, 
    }).then((response) => { 
     if (response.ok) { 
     return response.json().then((json) => { 
      dispatch({ 
      type: 'GET_COURSES', 
      courses: json.courses 
      }); 
     }) 
     } 
    }); 
    } 
} 

Reducer

export default function course(state={}, action) { 

    switch (action.type) { 
    case 'GET_COURSES': 
     return Object.assign({}, state, { 
     courses: action.courses 
     }) 
    default: 
     return state; 
    } 


} 

Komponente

import React from 'react'; 
import { Link } from 'react-router'; 
import { connect } from 'react-redux'; 


class Course extends React.Component { 



    allCourses() { 
    return this.props.courses.map((course) => { 
     return(
     <li>{ course.name }</li> 
    ); 

    }); 
    } 

    render() { 
    return (
     <div> 
     <ul> 
      { this.allCourses() } 
     </ul> 

     </div> 
    ) 
    } 
} 

const mapStateToProps = (state) => { 
    return { 
    courses: state.courses 
    } 
} 

export default connect(mapStateToProps)(Course); 

Indexreduzierer, wo ich alles

import { combineReducers } from 'redux'; 
import course from './course'; 

export default combineReducers({ 
    course, 
}); 

Configure Speicher kombinieren, wo ich speichern den intial Zustand und verkürzte

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

export default function configureStore(initialState) { 
    const store = createStore(
    rootReducer, 
    initialState, 
    compose(
     applyMiddleware(thunk), 
     typeof window == 'object' && typeof window.devToolsExtension !== 'undefined' ? window.devToolsExtension() : f => f 
    ) 
); 

    return store; 
} 

Ich glaube, warum die Daten dort nicht, weil ich ist die Aktion nicht aufgerufen? jede Hilfe würde geschätzt werden.

+0

Ist das Ihr nur Minderer? Oder kombinieren Sie Reducer anderswo? Können Sie uns zeigen, wo Sie das Geschäft initialisieren? –

Antwort

2

mapStateToProps den Wurzelzustand als Argument schreiben dauert (Ihr Indexreduzierer, die auch die Wurzel Minderer ist), nicht Ihre course Reduzierstück. Soweit ich das sagen kann, ist die Struktur Ihres Shops:

-index <- This is the root reducer 
    -course 

So von diesem Zustand die Kurse zu bekommen, in der Komponente:

// state is the state of the root reducer 
const mapStateToProps = (state) => { 
    return { 
    courses: state.course.courses 
    } 
} 

Auch könnten Sie den Zustand der Initialisierung der course Reducer mit einem leeren Array von Kursen, also wenn Sie die Komponente vor dem Abfeuern der Aktion rendern müssen, erhalten Sie den Fehler nicht.

const initialState = { 
    courses: [] 
}; 

export default function course(state= initialState, action) { 

    ... 

} 

Schließlich Sie Brennen nicht auf allen Aktion, so dass Sie nie wirklich die Kurse bekommen, ich nehme an, Sie wollen, dass sie abgerufen werden, sobald die Course Komponente geladen wird, für die Sie die componentDidMount verwenden können Ereignis in Ihrer Komponente.

Zunächst einmal müssen Sie die Aktion auf eine Eigenschaft der Komponente

// Make sure you import the action 
import { getCourses } from './pathToAction'; 

... 

const mapDispatchToProps = (dispatch) => { 
    return { 
    onGetCourses:() => dispatch(getCourses()) 
    }; 
} 

// Connect also with the dispatcher 
export default connect(masStateToProps, mapDispatchToProps)(Course); 

Nun rufen Sie die onGetCourses Eigenschaft zuzuordnen, wenn das Bauteil montiert

class Course extends React.Component { 

    componentDidMount() { 
     this.props.onGetCourses(); 
    } 

    ... 

} 
+0

Ich habe die Frage bereits mit zusätzlichen Informationen bearbeitet. Kurse ist definitiv ein Array. Ich habe es getestet und es gibt eine Reihe von Objekten zurück. – sinusGob

+0

Aber aus irgendeinem Grund, ich das Problem ist mit den Reduzierern oder die Aktion überhaupt nicht feuert – sinusGob

+0

@sinusGob Vielen Dank für den Rest des Codes! Ich habe meine Antwort bearbeitet, Sie hatten einen Fehler in der Komponente. –

1

sein, weil Requisiten können irgendwann nicht definiert werden, so dass Sie eine condtion wie diese

allCourses() { 
    if(this.props.courses){ 
    return this.props.courses.map((course) => { 
     return(
     <li>{ course.name }</li> 
    ); 
    }); 
    } 
    else { 
    return []; 
    } 
+0

die Requisiten sind undefiniert. Ist es, weil meine Aktion nicht feuert? – sinusGob

+0

Ja, das kann der Fall sein, Sie können die Erweiterung redux devtools verwenden, um zu überprüfen, ob Ihre Aktion ausgelöst wird oder nicht, außerdem sollten Sie den Anfangszustand so übergeben, dass Sie überprüfen können, ob Requisiten mit Daten gefüllt sind oder nicht. – abhirathore2006