Conversión de datos GraphQL para el componente CustomTreeData de DevExtreme-Reactive

Se necesitó aquí para mostrar los datos en forma de árbol, con la capacidad de editar diferentes campos, eliminar / agregar filas, etc. En el proceso de búsqueda de componentes adecuados (que quería encontrar en material-ui y reaccionar) comencé a intentar devextreme-reactivo . Sin embargo, Newans descubrió que devextreme-reactivo quiere los datos para el árbol como una matriz plana de objetos, cada uno de los cuales contiene el parent_id del "padre". Un servidor GraphQL me da un árbol en forma de objetos anidados con matrices de objetos. Tuve que hacer el otro de uno, tal vez alguien sea útil. O tal vez alguien dirá que no estaba confundido sobre el caso, y todo esto se hace mucho más fácil.

Entonces, en respuesta a la consulta GraphQL (hay pruebas, cada una tiene preguntas, para cada encuesta hay varias opciones de respuesta y queremos obtener todo de una vez):

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

Recibimos una respuesta del servidor del formulario:

Encabezado 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 normalizr :

En la descripción del esquema, a través de processStrategy, agregamos propiedades pid a los niños con enlaces a los padres. Por cierto, en la normalización reciente, la forma de describir los circuitos ha cambiado, por lo que los ejemplos con executeEntity, ArrayOf, define (que son muchos) son casi 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]}) 

Obtenemos esto:

Encabezado 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" ] } } 


Desde aquí solo nos interesan las entidades.

 const normalized = { entities: nRes.entities } 

Por cierto, en el proceso de ingresar a normalizr, después de leer los problemas, descubrí que no era el único que intentaba usarlo no exactamente para su propósito previsto (probablemente solo porque es casi la única herramienta de este tipo). Muchas personas anhelan todo tipo de características para obtener el resultado en el formato más personalizable. Pero los autores son de sílex.

En vista de lo anterior, el resultado de normalizr tendrá que aplanarse usando flat (expandimos recursivamente al nivel deseado de anidación):

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

Obtenemos lo siguiente:

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


Deshacerse de los índices:

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

Obtenemos:

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


Sería posible limpiar las matrices restantes de preguntas, las respuestas restantes aquí, pero estos son pequeños, no afectan la pantalla. Y __typename es necesario para que luego, al editar, comprendamos con qué estamos tratando.

En el componente, el resultado se procesa como se muestra en su ejemplo :

 ... <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 una alternativa a todo lo anterior puede ser leer directamente el contenido de la tienda GraphQL (en el cliente Apollo); todo también debe ser plano allí. Pero, para ser sincero, no encontré cómo se puede hacer esto de manera estándar, y no estoy muy seguro de que el formato en el que se almacenan los datos allí no cambie en las nuevas versiones.

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


All Articles