React - TypeError: this.props.courses.map ist keine Funktion

8

Ich habe eine react-redux-Anwendung erstellt. Momentan lädt es Kurse vom Server (api) und zeigt sie der Kurskomponente an. Das funktioniert perfekt. Ich versuche, eine Funktion hinzuzufügen, wo Sie einen Kurs erstellen können, indem Sie es auf dem Server veröffentlichen, der Server würde dann ein Erfolgsobjekt true. Wenn ich jedoch auf dem Server poste, erhalte ich den folgenden Fehler (siehe unten). Ich denke, das liegt an meiner connect-Anweisung, die auf die Last-Kurs-Aktion lauscht. Offensichtlich sollte es eine Liste von etwas anstatt eines Erfolgsobjekts bekommen. Ich habe ein paar Dinge ausprobiert, um auf beide Kurse und die Erfolgsantwort zu hören, aber um dir die Zeit zu sparen, all das seltsame zu lesen, was ich getan habe, konnte ich es nicht zur Arbeit bringen. Weiß jemand, wie man dieses Problem beheben kann?

Fehler

%Vor%

course.component.js

%Vor%

course.actions.js

%Vor%

course.reducer.js

%Vor%

server.js

%Vor%

Ich habe versucht, eine Antwort auf den Staat hinzugefügt, und lauschte im Requisiten auf den Kartenstatus, aber immer noch aus irgendeinem Grund versucht reagieren Antwort auf Kurse. Brauche ich eine zweite Verbindungsmethode?

%Vor%

Wie Sie aus den Bildern sehen können, wird die Antwort als Kurs und nicht als Antwort zugeordnet.

Bild

Link incase stack wird es nicht anzeigen. Kurse: Ссылка

Antwort: Ссылка

    
John 07.06.2017, 16:38
quelle

3 Antworten

3

Annahmen:

  1. state.courses ist anfänglich ein leeres Array - aus course.reducer.js
  2. Sie rufen fetchCourses() action nicht beim ersten Rendern Ihrer Ansicht auf
  3. Auch wenn Sie fetchCourses() aufrufen, gibt es kein Problem, solange courses in server.js ein Array ist (das Array in der Antwort ersetzt das ursprüngliche state.courses )

Fluss:
Jetzt gehe ich davon aus, dass das erste Rendering erfolgreich ist und React die Schaltfläche <input type="text"> und submit anzeigt. Wenn Sie nun den Titel eingeben und auf die Schaltfläche submit klicken, löst die Methode onSave() die Aktion createCourse() mit einem Parameter aus, der mehr oder weniger mit { title: 'something' } übereinstimmt.

Dann serialisieren Sie den oben genannten Parameter und senden ihn an den Server (in course.actions.js - & gt; createCourse() ), was wiederum eine Antwort zurückgibt, die aussieht wie {response: 200} (in server.js). Antwortfeld ist eine Ganzzahl und kein -Array! Weiter gehend rufen Sie loadCourses() mit dem Objekt {response: 200} auf, was% code_de% in course.reducer.js

auslöst

Das courseReducer ersetzt courseReducer() (welches [[] gemäß Annahme ist) mit einer Ganzzahl. Und diese Statusaktualisierung löst ein erneutes Rendern aus und Sie rufen state.courses für eine Ganzzahl und nicht für ein Array auf, was zu map() führt.

Mögliche Lösung:

  1. Gib eine gültige Antwort von serve.js zurück (d. h. gib das TypeError: this.props.courses.map is not a function -Objekt zurück, mit dem der Endpunkt aufgerufen wurde), oder
  2. Aktualisieren Sie Ihren Reducer, um das neue Kursobjekt in das vorhandene Array course einzufügen, z. B. state.courses

Aktualisierung:

Wenn Sie auf der Grundlage des OP-Kommentars das neue Kursobjekt an den Server senden möchten, validieren Sie es und senden Sie den Erfolg (oder Fehler) und fügen Sie auf der Grundlage der Antwort das gleiche Kursobjekt der vorherigen Kursliste hinzu Sie können einfach return [...state, action.response] mit demselben loadData() -Objekt aufrufen, das Sie course genannt haben, und (wie oben erwähnt) in Ihrem Reducer, anstatt das alte Array zu ersetzen oder mutieren ein neues Array zu erstellen und das Kursobjekt daran anzufügen, In es6 können Sie etwas wie createCourse() tun.

Aktualisierung 2:

Ich schlage vor, Sie gehen durch Redux Doc . Zitieren von Redux-Aktionen 'Doc

  

Aktionen sind Nutzinformationen von Informationen , die Daten von Ihrer Anwendung an Ihr Geschäft senden. Sie sind die einzige Informationsquelle für den Laden.

Die Aktion return [...state, course] wird mit einer Nutzlast aufgerufen, die mehr oder weniger wie folgt aussieht, und Sie rufen Ihren Server mit einer AJAX-Anforderung auf und übergeben das < em> Nutzlast an den Server, der dann die Nutzdaten validiert und basierend auf Ihrer Logik eine Erfolgs- (oder Fehler-) Antwort sendet. Die Serverantwort sieht wie folgt aus: createCourse() . Dies ist das Ende der Aktion {title: 'Thing you entered in Text Field'} . Jetzt haben Sie {response: 200} createCourse() Aktion von dispatch() mit der Antwort, die Sie vom Server erhalten haben, was Sie nicht wollen (basierend auf Ihren Kommentaren). Also, versuchen Sie stattdessen loadCourses() in der Aktion wie folgt (versuchen Sie, createCorse() param umzubenennen, es ist ein bisschen verwirrend)

%Vor%

Nun ist dispatch() eine sehr einfache Aktion und leitet einfach die Argumente weiter, die Redux verwendet, um Ihre response aufzurufen. Nun, falls Sie die vorherige Diskussion befolgt haben und aktualisieren, wie Sie loadCourse() aufrufen, dann sieht die Rückgabe von reducer wie

aus %Vor%

wird dann an Ihr loadCourse() übergeben, insbesondere an Ihr loadCourse() .

Zitiert erneut aus Redux Reducers 'Doc

  

Aktionen beschreiben die Tatsache, dass etwas passiert ist, aber nicht angeben , wie sich der Status der Anwendung ändert . Dies ist die Aufgabe von Reduzierern.

Das reducer muss die Logik definieren, wie sich die Aktion auf die Daten in courseReducer() auswirken soll.
In deinem reducer gibst du einfach das store -Feld innerhalb des courseReducer() -Objekts zurück und [expect] Redux, um deinen Zustand automatisch zu verändern! Leider passiert das nicht :(
Was auch immer du von dem Reduzierer zurückbringst, ersetzt alles was vorher da war, wie wenn dein Zustand so aussieht.

%Vor%

und du gibst so etwas von deinem Reduzierer zurück

%Vor%

dann wird redux den Zustand so aktualisieren, dass er aussieht wie

%Vor%

state.courses ist kein Array mehr!

Lösung:
Ändern Sie Ihren Reducer zu etwas wie diesem

%Vor%

Seitennotiz : Dies kann manchmal verwirrend sein, daher ist response in action nicht der vollständige Status, sondern state in courseReducer() , die property verwaltet. Sie können mehr darüber hier

lesen     
riyaz-ali 10.06.2017, 06:38
quelle
1

- Bearbeiten Sie nach dem Lesen eines Kommentars von Ihnen in einer anderen Antwort, ich habe meine vorherige Antwort geschabt -

Was Sie gerade mit Ihren Aktionen und Reduzierungen machen, ist, dass Sie loadCourse aufrufen, wenn Sie die ersten Kurse abgerufen haben. Und wenn Sie einen neuen Kurs erstellt haben, rufen Sie auch loadCourse auf.

In Ihrem Reducer geben Sie direkt die Antwort Ihres API-Aufrufs zurück. Wenn Sie also alle Kurse abrufen, erhalten Sie eine vollständige Liste aller Ihrer Kurse. Wenn Sie jedoch eine neue erstellen, erhalten Sie aktuell ein Objekt mit dem Namen response: 200 . Object s haben keine Kartenfunktion, was Ihren Fehler erklärt.

Ich würde vorschlagen, res.status(200).json() für Ihre API zu verwenden und den Antwortstatus in Ihrem Frontend zu wechseln (oder then und catch zu verwenden, wenn Sie den Antwortstatus validieren können, axios hat diese Funktionalität ( validateStatus )).

Als nächstes würde ich einen separaten Aktionstyp erstellen, um Posts zu erstellen und zu versenden, wann immer es erfolgreich ist.

Ich würde Ihren Reducer in etwas wie

ändern %Vor%

Es würde mir nichts ausmachen, in Ihr Projekt zu schauen und Ihnen ein Feedback zu geben, wie Sie einige Dinge verbessern können (ES6'ing, Best Practices, allgemeine Sachen)

    
Alserda 16.06.2017 11:09
quelle
1

Basierend auf den Fragen & amp; Bis jetzt sieht es so aus, als müssten Sie so etwas tun:

1) Fügen Sie eine neue Aktion hinzu und senden Sie diese aus Ihrer createCourse-Funktion

%Vor%

2) Ändern Sie Ihre Reduzierungen, um sowohl Kurse abzurufen als auch einen neuen Kurs hinzuzufügen (wir verwenden combinateReducers , um dies hier zu behandeln)

%Vor%

3) Verbinden Sie sich mit dem neuen response -Zustand in Ihrer connect -Komponente

%Vor%

4) Machen Sie etwas mit dieser neuen Property response in Ihrer Komponente, wenn Sie sie z. B. anzeigen möchten.

%Vor%

AKTUALISIEREN

Ich habe Unterstützung hinzugefügt, um den neuen Kurs am Ende der vorhandenen Kursliste hinzuzufügen und die Antwort zu bearbeiten. Wie Sie den Zustand gestalten, liegt ganz bei Ihnen und kann entsprechend angepasst werden.

Damit dieser Code funktioniert, müssen Sie Unterstützung für den Spread hinzufügen Betreiber . Wenn du Babel benutzt, kann es wie das gemacht werden. Das Erstellen eines neuen Objekts ist wichtig, um sicherzustellen, dass Sie den vorhandenen Status nicht ändern. Es wird auch bedeuten, dass reaktiv-redux weiß, dass sich der Zustand geändert hat. Spread-Operator ist nicht essentiell und dies kann mit Object.assign gemacht werden, aber diese Syntax ist hässlich IMO.

    
Michael 16.06.2017 17:24
quelle