Il a fallu ici pour afficher les données sous la forme d'un arbre, avec la possibilité de modifier différents champs, supprimer / ajouter des lignes, etc. Dans le processus de recherche de composants appropriés (je voulais trouver sous
Material- ui et réagir), j'ai commencé à essayer
devextreme-reactive . Cependant, Newans a constaté que devextreme-reactive veut que les données de l'arbre soient un tableau plat d'objets, chacun contenant le parent_id du «parent». Un serveur GraphQL me donne un arbre sous forme d'objets imbriqués avec des tableaux d'objets. Je devais faire l'autre sur un - peut-être que quelqu'un viendra à portée de main. Ou peut-être que quelqu'un dira que je n'étais pas confus à propos de l'affaire, et tout cela est beaucoup plus facile.
Donc, en réponse à la requête GraphQL (il y a des tests, chacun a des questions, pour chaque enquête il y a plusieurs options de réponse et nous voulons tout obtenir en même temps):
query TestQuery { tests { id title questions { id title answers { id title } } } }
Nous obtenons une réponse du serveur du formulaire:
Cap de spoiler { "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": [] } ] } }
Pour normaliser, utilisez
normalizr :
Dans la description du schéma, via processStrategy, nous ajoutons des propriétés pid aux enfants avec des liens vers les parents. Soit dit en passant, dans une nouvelle normalisation, la façon de décrire les circuits a changé, à cause de laquelle les exemples avec assignEntity, ArrayOf, define (qui sont nombreux) sont presque hors de propos.
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]})
Nous obtenons ceci:
Cap de spoiler { "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" ] } }
À partir d'ici, nous ne nous intéressons qu'aux entités.
const normalized = { entities: nRes.entities }
Au fait, en entrant dans normalizr, après avoir lu les problèmes, j'ai découvert que je n'étais pas le seul à essayer de l'utiliser à d'autres fins (probablement juste parce que c'est presque le seul outil de ce type). Beaucoup de gens recherchent toutes sortes de fonctionnalités afin d'obtenir le résultat dans le format le plus personnalisable. Mais les auteurs sont en silex.
Au vu de ce qui précède, le résultat de la normalisation devra être aplati à l'aide de
flat (nous étendons récursivement au niveau d'imbrication souhaité):
const flattened = flatten({ entities: nRes.entities }, { maxDepth: 3 })
Nous obtenons ce qui suit:
Cap de spoiler { "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 } }
Se débarrasser des indices:
Object.keys(flattened).forEach( (key)=> rows.push(flattened[key]) )
Nous obtenons:
Cap de spoiler [ { "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 } ]
Il serait possible de nettoyer les tableaux de questions restants, les réponses restant ici, mais ce sont des bagatelles - elles n'affectent pas l'affichage. Et __typename est nécessaire pour que plus tard, lors de l'édition, nous comprenions à quoi nous avons affaire.
Dans le composant, le résultat est traité comme indiqué dans leur
exemple :
... <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 } ...
Il semble qu'une alternative à tout ce qui précède peut être de lire directement le contenu de la boutique GraphQL (dans le client Apollo) - tout
devrait également y
être plat. Mais, pour être honnête, je n'ai pas trouvé comment cela peut être fait de manière standard, et je ne suis pas très sûr que le format dans lequel les données sont stockées ne changera pas dans les nouvelles versions.