Conversão de dados GraphQL para o componente CustomTreeData do DevExtreme-Reactive

Foi necessário aqui para exibir os dados na forma de uma árvore, com a capacidade de editar campos diferentes, excluir / adicionar linhas, etc. No processo de busca de componentes adequados (eu queria encontrar sob material-ui e reagir), comecei a tentar o reativo ao extremo . No entanto, Newans descobriu que devextreme-reactive deseja os dados para a árvore como uma matriz plana de objetos, cada um dos quais contém o parent_id do "parent". Um servidor GraphQL me fornece uma árvore na forma de objetos aninhados com matrizes de objetos. Eu tive que fazer o outro de um - talvez alguém seja útil. Ou talvez alguém diga que não fiquei confuso sobre o caso, e tudo isso é feito com muito mais facilidade.

Portanto, em resposta à consulta do GraphQL (existem testes, cada um tem perguntas, para cada pesquisa existem várias opções de resposta e queremos obter tudo de uma vez):

query TestQuery { tests { id title questions { id title answers { id title } } } } 

Recebemos uma resposta do servidor do formulário:

Título 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": [] } ] } } 


Para normalizar, use o normalizr :

Na descrição do esquema, por meio do processStrategy, adicionamos propriedades pid a crianças com links para os pais. A propósito, em uma nova normalização, a maneira de descrever os circuitos mudou, por causa dos quais os exemplos com assignEntity, ArrayOf, define (que são muitos) são quase irrelevantes.

 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]}) 

Temos isso:

Título 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" ] } } 


A partir daqui, estamos interessados ​​apenas em .entities

 const normalized = { entities: nRes.entities } 

A propósito, no processo de inserção do normalizr, depois de ler os problemas, descobri que não era o único a tentar usá-lo não exatamente para o objetivo pretendido (provavelmente apenas porque é quase a única ferramenta desse tipo). Muitas pessoas desejam todos os tipos de recursos para obter o resultado no formato mais personalizável. Mas os autores são sílex.

Tendo em vista o exposto acima, o resultado do normalizr precisará ser nivelado usando flat (expandimos recursivamente para o nível desejado de aninhamento):

 const flattened = flatten({ entities: nRes.entities }, { maxDepth: 3 }) 

Temos o seguinte:

Título 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 } } 


Livrar-se dos índices:

 Object.keys(flattened).forEach( (key)=> rows.push(flattened[key]) ) 

Temos:

Título 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 } ] 


Seria possível limpar as matrizes restantes de perguntas, respostas restantes aqui, mas essas são triviais - elas não afetam a exibição. E __typename é necessário para que, posteriormente, ao editar, entendamos com o que estamos lidando.

No componente, o resultado é processado conforme mostrado no exemplo :

 ... <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 } ... 

Parece que uma alternativa a todas as opções acima pode ser ler diretamente o conteúdo da loja GraphQL (no cliente Apollo) - tudo também deve estar simples lá. Mas, para ser sincero, não descobri como isso pode ser feito de maneira padrão e não tenho muita certeza de que o formato no qual os dados são armazenados não seja alterado em novas versões.

Source: https://habr.com/ru/post/pt416111/


All Articles