Hier wurden die Daten in Form eines Baums angezeigt, mit der Möglichkeit, verschiedene Felder zu bearbeiten, Zeilen zu löschen / hinzuzufügen usw. Bei der Suche nach geeigneten Komponenten (die ich unter
material-ui finden und reagieren wollte) begann ich,
devextreme-reaktiv zu versuchen. Newans stellte jedoch fest, dass devextreme-reaktiv die Daten für den Baum als flaches Array von Objekten haben möchte, von denen jedes die parent_id des „parent“ enthält. Ein GraphQL-Server gibt mir einen Baum in Form von verschachtelten Objekten mit Arrays von Objekten. Ich musste den anderen aus dem einen machen - vielleicht wird jemand nützlich sein. Oder vielleicht wird jemand sagen, dass ich über den Fall nicht verwirrt war, und das alles ist viel einfacher.
Als Antwort auf die GraphQL-Abfrage (es gibt Tests, jeder hat Fragen, für jede Umfrage gibt es mehrere Antwortoptionen und wir möchten alles auf einmal erhalten):
query TestQuery { tests { id title questions { id title answers { id title } } } }
Wir erhalten eine Antwort vom Server des Formulars:
Spoiler Überschrift { "data": { "tests": [ { "id": "test_1", "title": "Test 1", "questions": [ { "id": "question_1", "title": "Question 1 (for t1)", "answers": [ { "id": "answer_1", "title": "Answer 1 (for q1)" }, { "id": "answer_2", "title": "Answer 2 (for q1)" } ] }, { "id": "question_2", "title": "Question 2 (for t1)", "answers": [ { "id": "answer_1_2", "title": "Answer 1 (for q2)" } ] } ] }, { "id": "test_2", "title": "Test 2", "questions": [ { "id": "question_1_2", "title": "Question 1 (for t2)", "answers": [] } ] }, { "id": "test_3", "title": "Test 3", "questions": [] } ] } }
Verwenden Sie zum
Normalisieren normalizr :
In der Beschreibung des Schemas fügen wir über processStrategy Kindern PID-Eigenschaften mit Links zu Eltern hinzu. Übrigens hat sich in frischem Normalismus die Art der Beschreibung von Schaltkreisen geändert, weshalb die Beispiele mit assignEntity, ArrayOf, define (die viele sind) fast irrelevant sind.
const answerSchema = new schema.Entity('answers',{}, { processStrategy: (entity, parent, key) => { return { ...entity, pid: parent.id} } } ) const questionSchema = new schema.Entity('questions',{ answers:[answerSchema]}, { processStrategy: (entity, parent, key) => { return { ...entity, pid: parent.id} } }, ) const testSchema = new schema.Entity('tests',{questions:[questionSchema]}, { processStrategy: (entity, parent, key) => { return { ...entity, pid: 0 } } } ) const nRes = normalize(result.data, {tests: [testSchema]})
Wir bekommen das:
Spoiler Überschrift { "entities": { "answers": { "answer_1": { "id": "answer_1", "title": "Answer 1 (for q1)", "__typename": "Answer", "pid": "question_1" }, "answer_2": { "id": "answer_2", "title": "Answer 2 (for q1)", "__typename": "Answer", "pid": "question_1" }, "answer_1_2": { "id": "answer_1_2", "title": "Answer 1 (for q2)", "__typename": "Answer", "pid": "question_2" } }, "questions": { "question_1": { "id": "question_1", "title": "Question 1 (for t1)", "answers": [ "answer_1", "answer_2" ], "__typename": "Question", "pid": "test_1" }, "question_2": { "id": "question_2", "title": "Question 2 (for t1)", "answers": [ "answer_1_2" ], "__typename": "Question", "pid": "test_1" }, "question_1_2": { "id": "question_1_2", "title": "Question 1 (for t2)", "answers": [ ], "__typename": "Question", "pid": "test_2" } }, "tests": { "test_1": { "id": "test_1", "title": "Test 1", "questions": [ "question_1", "question_2" ], "__typename": "Test", "pid": 0 }, "test_2": { "id": "test_2", "title": "Test 2", "questions": [ "question_1_2" ], "__typename": "Test", "pid": 0 }, "test_3": { "id": "test_3", "title": "Test 3", "questions": [ ], "__typename": "Test", "pid": 0 } } }, "result": { "tests": [ "test_1", "test_2", "test_3" ] } }
Von hier aus interessieren wir uns nur noch für .entities
const normalized = { entities: nRes.entities }
Übrigens stellte ich beim Auslesen von normalizr fest, dass ich nicht der einzige war, der versuchte, es nicht ganz für den beabsichtigten Zweck zu verwenden (wahrscheinlich nur, weil es fast das einzige derartige Werkzeug ist). Viele Menschen sehnen sich nach allen möglichen Funktionen, um das Ergebnis im anpassbarsten Format zu erhalten. Aber die Autoren sind Feuerstein.
In Anbetracht des oben Gesagten muss das Ergebnis von normalizr mit
flat abgeflacht werden (wir erweitern es rekursiv auf das gewünschte Verschachtelungsniveau):
const flattened = flatten({ entities: nRes.entities }, { maxDepth: 3 })
Wir bekommen folgendes:
Spoiler Überschrift { "entities.answers.answer_1": { "id": "answer_1", "title": "Answer 1 (for q1)", "__typename": "Answer", "pid": "question_1" }, "entities.answers.answer_2": { "id": "answer_2", "title": "Answer 2 (for q1)", "__typename": "Answer", "pid": "question_1" }, "entities.answers.answer_1_2": { "id": "answer_1_2", "title": "Answer 1 (for q2)", "__typename": "Answer", "pid": "question_2" }, "entities.questions.question_1": { "id": "question_1", "title": "Question 1 (for t1)", "answers": [ "answer_1", "answer_2" ], "__typename": "Question", "pid": "test_1" }, "entities.questions.question_2": { "id": "question_2", "title": "Question 2 (for t1)", "answers": [ "answer_1_2" ], "__typename": "Question", "pid": "test_1" }, "entities.questions.question_1_2": { "id": "question_1_2", "title": "Question 1 (for t2)", "answers": [ ], "__typename": "Question", "pid": "test_2" }, "entities.tests.test_1": { "id": "test_1", "title": "Test 1", "questions": [ "question_1", "question_2" ], "__typename": "Test", "pid": 0 }, "entities.tests.test_2": { "id": "test_2", "title": "Test 2", "questions": [ "question_1_2" ], "__typename": "Test", "pid": 0 }, "entities.tests.test_3": { "id": "test_3", "title": "Test 3", "questions": [ ], "__typename": "Test", "pid": 0 } }
Indizes loswerden:
Object.keys(flattened).forEach( (key)=> rows.push(flattened[key]) )
Wir bekommen:
Spoiler Überschrift [ { "id": "answer_1", "title": "Answer 1 (for q1)", "__typename": "Answer", "pid": "question_1" }, { "id": "answer_2", "title": "Answer 2 (for q1)", "__typename": "Answer", "pid": "question_1" }, { "id": "answer_1_2", "title": "Answer 1 (for q2)", "__typename": "Answer", "pid": "question_2" }, { "id": "question_1", "title": "Question 1 (for t1)", "answers": [ "answer_1", "answer_2" ], "__typename": "Question", "pid": "test_1" }, { "id": "question_2", "title": "Question 2 (for t1)", "answers": [ "answer_1_2" ], "__typename": "Question", "pid": "test_1" }, { "id": "question_1_2", "title": "Question 1 (for t2)", "answers": [ ], "__typename": "Question", "pid": "test_2" }, { "id": "test_1", "title": "Test 1", "questions": [ "question_1", "question_2" ], "__typename": "Test", "pid": 0 }, { "id": "test_2", "title": "Test 2", "questions": [ "question_1_2" ], "__typename": "Test", "pid": 0 }, { "id": "test_3", "title": "Test 3", "questions": [ ], "__typename": "Test", "pid": 0 } ]
Es wäre möglich, die verbleibenden Fragenfelder und Antworten zu bereinigen, aber dies sind Kleinigkeiten - sie wirken sich nicht auf die Anzeige aus. Und __typename wird benötigt, damit wir später beim Bearbeiten verstehen, womit wir es zu tun haben.
In der Komponente wird das Ergebnis wie in ihrem
Beispiel gezeigt verarbeitet:
... <CustomTreeData getChildRows={getChildRows} /> ... const getChildRows = (currentRow, rootRows) => { const childRows = rootRows.filter(r => r.pid === (currentRow ? currentRow.id : 0)); const res = childRows.length ? childRows : null return res } ...
Es scheint, dass eine Alternative zu all dem darin besteht, den Inhalt des GraphQL-Speichers (im Apollo-Client) direkt zu lesen - dort
sollte auch
alles flach sein. Aber um ehrlich zu sein, habe ich nicht herausgefunden, wie dies auf übliche Weise gemacht werden kann, und ich bin mir nicht sicher, ob sich das Format, in dem die Daten dort gespeichert sind, in neuen Versionen nicht ändern wird.