рдкреЗрдбрд╝ рдХреЗ рд░реВрдк рдореЗрдВ рдбреЗрдЯрд╛ рдХреЛ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдиреЗ, рд╡рд┐рднрд┐рдиреНрди рдХреНрд╖реЗрддреНрд░реЛрдВ рдХреЛ рд╕рдВрдкрд╛рджрд┐рдд рдХрд░рдиреЗ, рдкрдВрдХреНрддрд┐рдпреЛрдВ рдХреЛ рд╣рдЯрд╛рдиреЗ / рдЬреЛрдбрд╝рдиреЗ рдЖрджрд┐ рдХреА рдХреНрд╖рдорддрд╛ рдХреЗ рд▓рд┐рдП рдпрд╣ рдпрд╣рд╛рдБ рд▓рд┐рдпрд╛ рдЧрдпрд╛ред рдЙрдкрдпреБрдХреНрдд рдШрдЯрдХреЛрдВ рдХреА рдЦреЛрдЬ рдХреА рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдореЗрдВ (рдореИрдВ
рд╕рд╛рдордЧреНрд░реА-рдпреВрдЖрдИ рдФрд░ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдХреЗ рддрд╣рдд рдЦреЛрдЬрдирд╛ рдЪрд╛рд╣рддрд╛ рдерд╛) рдореИрдВрдиреЗ
рдбреЗрд╡реЗрдХреНрд╕реНрдЯреНрд░реАрдо-рд░рд┐рдПрдХреНрдЯрд┐рд╡ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░рдирд╛ рд╢реБрд░реВ рдХрд░ рджрд┐рдпрд╛ред рд╣рд╛рд▓рд╛рдВрдХрд┐, рдиреНрдпреВрдиреНрд╕ рдиреЗ рдкрд╛рдпрд╛ рдХрд┐ рдбреЗрд╡реЗрдХреНрд╕реНрдЯреНрд░реАрдо-рд░рд┐рдПрдХреНрдЯрд┐рд╡, рдЯреНрд░реА рдХреЗ рд▓рд┐рдП рдбреЗрдЯрд╛ рдХреЛ рдСрдмреНрдЬреЗрдХреНрдЯреНрд╕ рдХреЗ рдПрдХ рдлреНрд▓реИрдЯ рдРрд░реЗ рдХреЗ рд░реВрдк рдореЗрдВ рдЪрд╛рд╣рддрд╛ рд╣реИ, рдЬрд┐рдирдореЗрдВ рд╕реЗ рдкреНрд░рддреНрдпреЗрдХ рдореЗрдВ "рдкреИрд░реЗрдВрдЯ" рдХрд╛ рдкреЗрд░реЗрдВрдЯ_рдб рд╣реЛрддрд╛ рд╣реИред рдПрдХ GraphQL рд╕рд░реНрд╡рд░ рдореБрдЭреЗ рдСрдмреНрдЬреЗрдХреНрдЯреНрд╕ рдХреЗ рд╕рд░рдгрд┐рдпреЛрдВ рдХреЗ рд╕рд╛рде рдиреЗрд╕реНрдЯреЗрдб рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЗ рд░реВрдк рдореЗрдВ рдПрдХ рдкреЗрдбрд╝ рджреЗрддрд╛ рд╣реИред рдореБрдЭреЗ рджреВрд╕рд░реЗ рдХреЛ рдПрдХ рдХрд░рдирд╛ рдерд╛ - рд╢рд╛рдпрдж рдХреЛрдИ рдХрд╛рдо рдЖрдПрдЧрд╛ред рдпрд╛ рд╢рд╛рдпрдж рдХреЛрдИ рдХрд╣реЗрдЧрд╛ рдХрд┐ рдореИрдВ рдорд╛рдорд▓реЗ рдХреЛ рд▓реЗрдХрд░ рднреНрд░рдорд┐рдд рдирд╣реАрдВ рдерд╛, рдФрд░ рдпрд╣ рд╕рдм рдмрд╣реБрдд рдЖрд╕рд╛рди рд╣реИред
рдЗрд╕рд▓рд┐рдП, рдЧреНрд░рд╛рдлрдХреНрдпреВрдПрд▓ рдХреНрд╡реЗрд░реА рдХреЗ рдЬрд╡рд╛рдм рдореЗрдВ (рдкрд░реАрдХреНрд╖рдг рд╣реИрдВ, рдкреНрд░рддреНрдпреЗрдХ рдореЗрдВ рдкреНрд░рд╢реНрди рд╣реИрдВ, рдкреНрд░рддреНрдпреЗрдХ рд╕рд░реНрд╡реЗрдХреНрд╖рдг рдХреЗ рд▓рд┐рдП рдХрдИ рдЙрддреНрддрд░ рд╡рд┐рдХрд▓реНрдк рд╣реИрдВ рдФрд░ рд╣рдо рдПрдХ рд╣реА рдмрд╛рд░ рдореЗрдВ рд╕рдм рдХреБрдЫ рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ):
query TestQuery { tests { id title questions { id title answers { id title } } } }
рд╣рдореЗрдВ рдлреЙрд░реНрдо рдХреЗ рд╕рд░реНрд╡рд░ рд╕реЗ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдорд┐рд▓рддреА рд╣реИ:
рд╕реНрдкрд╛рдпрд▓рд░ рд╣реЗрдбрд┐рдВрдЧ { "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": [] } ] } }
рд╕рд╛рдорд╛рдиреНрдп рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, normalizr рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ:
рдпреЛрдЬрдирд╛ рдХреЗ рд╡рд┐рд╡рд░рдг рдореЗрдВ, рдкреНрд░рдХреНрд░рд┐рдпрд╛рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ, рд╣рдо рдорд╛рддрд╛-рдкрд┐рддрд╛ рдХреЗ рд▓рд┐рдВрдХ рд╡рд╛рд▓реЗ рдмрдЪреНрдЪреЛрдВ рдХреЗ рд▓рд┐рдП рдкрд┐рдб рдЧреБрдг рдЬреЛрдбрд╝рддреЗ рд╣реИрдВред рд╡реИрд╕реЗ, рд╕рд╛рдорд╛рдиреНрдп рдиреЙрд░реНрдорд┐рдЬрд╝реНрд░ рдореЗрдВ рд╕рд░реНрдХрд┐рдЯ рдХрд╛ рд╡рд░реНрдгрди рдХрд░рдиреЗ рдХрд╛ рддрд░реАрдХрд╛ рдмрджрд▓ рдЧрдпрд╛ рд╣реИ, рдЬрд┐рд╕рдХреЗ рдХрд╛рд░рдг рдЕрд╕рд╛рдЗрдирдореЗрдВрдЯ, рдЕрд░реНрд░реЗрдСрдл, рдбрд┐рдлрд╛рдЗрди (рдЬреЛ рдХрдИ рд╣реИрдВ) рдХреЗ рд╕рд╛рде рдЙрджрд╛рд╣рд░рдг рд▓рдЧрднрдЧ рдЕрдкреНрд░рд╛рд╕рдВрдЧрд┐рдХ рд╣реИрдВред
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]})
рд╣рдореЗрдВ рдпрд╣ рдорд┐рд▓рддрд╛ рд╣реИ:
рд╕реНрдкрд╛рдпрд▓рд░ рд╣реЗрдбрд┐рдВрдЧ { "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" ] } }
рдпрд╣рд╛рдБ рд╕реЗ рд╣рдо рдХреЗрд╡рд▓ .entities рдореЗрдВ рд░реБрдЪрд┐ рд░рдЦрддреЗ рд╣реИрдВ
const normalized = { entities: nRes.entities }
рд╡реИрд╕реЗ, рдиреЙрд░реНрдорд┐рдЬрд╝реНрд░ рдореЗрдВ рдкреНрд░рд╡реЗрд╢ рдХрд░рдиреЗ рдХреА рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдореЗрдВ, рдореБрджреНрджреЛрдВ рдХреЛ рдкрдврд╝рдиреЗ рдХреЗ рдмрд╛рдж, рдореБрдЭреЗ рдкрддрд╛ рдЪрд▓рд╛ рдХрд┐ рдореИрдВ рдПрдХрдорд╛рддреНрд░ рдРрд╕рд╛ рдирд╣реАрдВ рдерд╛ рдЬреЛ рдЗрд╕реЗ рдЕрдкрдиреЗ рдЗрдЪреНрдЫрд┐рдд рдЙрджреНрджреЗрд╢реНрдп рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░ рд░рд╣рд╛ рдерд╛ (рд╢рд╛рдпрдж рд╕рд┐рд░реНрдл рдЗрд╕рд▓рд┐рдП рдХрд┐ рдпрд╣ рд▓рдЧрднрдЧ рдПрдХрдорд╛рддреНрд░ рдРрд╕рд╛ рдЙрдкрдХрд░рдг рд╣реИ)ред рдХрдИ рд▓реЛрдЧ рд╕рдмрд╕реЗ рдЕрдиреБрдХреВрд▓рди рдкреНрд░рд╛рд░реВрдк рдореЗрдВ рдкрд░рд┐рдгрд╛рдо рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╕рднреА рдкреНрд░рдХрд╛рд░ рдХреА рд╕реБрд╡рд┐рдзрд╛рдУрдВ рдХреЛ рддрд░рд╕рддреЗ рд╣реИрдВред рд▓реЗрдХрд┐рди рд▓реЗрдЦрдХ рдЪрдХрдордХ рд╣реИрдВред
рдЙрдкрд░реЛрдХреНрдд рдХреЗ рдорджреНрджреЗрдирдЬрд░,
рдлреНрд▓реИрдЯ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдиреЙрд░реНрдорд┐рдЬрд╝реНрд░ рдХреЗ рдкрд░рд┐рдгрд╛рдо рдХреЛ
рд╕рдорддрд▓ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ (рд╣рдо рдкреБрдирд░рд╛рд╡рд░реНрддреА рд░реВрдк рд╕реЗ рдШреЛрдВрд╕рд▓реЗ рдХреЗ рд╡рд╛рдВрдЫрд┐рдд рд╕реНрддрд░ рддрдХ рд╡рд┐рд╕реНрддрд╛рд░ рдХрд░реЗрдВрдЧреЗ):
const flattened = flatten({ entities: nRes.entities }, { maxDepth: 3 })
рд╣рдо рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдкреНрд░рд╛рдкреНрдд рдХрд░рддреЗ рд╣реИрдВ:
рд╕реНрдкрд╛рдпрд▓рд░ рд╣реЗрдбрд┐рдВрдЧ { "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 } }
рд╕реВрдЪрдХрд╛рдВрдХреЛрдВ рд╕реЗ рдЫреБрдЯрдХрд╛рд░рд╛:
Object.keys(flattened).forEach( (key)=> rows.push(flattened[key]) )
рд╣рдореЗрдВ рдорд┐рд▓рддрд╛ рд╣реИ:
рд╕реНрдкрд╛рдпрд▓рд░ рд╣реЗрдбрд┐рдВрдЧ [ { "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 } ]
рдпрд╣рд╛рдВ рд╢реЗрд╖ рдкреНрд░рд╢реНрдиреЛрдВ, рдЙрддреНрддрд░реЛрдВ рдХреЗ рд╢реЗрд╖ рд╕рд░рдгрд┐рдпреЛрдВ рдХреЛ рд╕рд╛рдл рдХрд░рдирд╛ рд╕рдВрднрд╡ рд╣реЛрдЧрд╛, рд▓реЗрдХрд┐рди рдпреЗ рдЯреНрд░рд╛рдЗрдлрд▓реНрд╕ рд╣реИрдВ - рд╡реЗ рдкреНрд░рджрд░реНрд╢рди рдХреЛ рдкреНрд░рднрд╛рд╡рд┐рдд рдирд╣реАрдВ рдХрд░рддреЗ рд╣реИрдВред рдФрд░ __typename рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ рддрд╛рдХрд┐ рдмрд╛рдж рдореЗрдВ рдЬрдм рд╕рдВрдкрд╛рджрди рд╣реЛ рддреЛ рд╣рдо рд╕рдордЭреЗрдВ рдХрд┐ рд╣рдо рдХреНрдпрд╛ рд╡реНрдпрд╡рд╣рд╛рд░ рдХрд░ рд░рд╣реЗ рд╣реИрдВред
рдШрдЯрдХ рдореЗрдВ, рдкрд░рд┐рдгрд╛рдо рдХреЛ рдЙрдирдХреЗ
рдЙрджрд╛рд╣рд░рдг рдореЗрдВ рджрд┐рдЦрд╛рдпрд╛ рдЧрдпрд╛ рд╣реИ:
... <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 } ...
рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдЙрдкрд░реЛрдХреНрдд рд╕рднреА рдХреЗ рд▓рд┐рдП рдПрдХ рд╡рд┐рдХрд▓реНрдк рд╣реЛ рд╕рдХрддрд╛ рд╣реИ рдХрд┐ рдЖрдк рд╕реАрдзреЗ рдЧреНрд░рд╛рдлрд╝рд┐рдХрд▓ рд╕реНрдЯреЛрд░ рдХреА рд╕рд╛рдордЧреНрд░реА (рдЕрдкреЛрд▓реЛ рдХреНрд▓рд╛рдЗрдВрдЯ рдореЗрдВ) рдХреЛ рдкрдврд╝ рд╕рдХреЗрдВ - рд╡рд╣рд╛рдВ рднреА рд╕рдм рдХреБрдЫ рд╕рдорддрд▓
рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП ред рд▓реЗрдХрд┐рди, рдИрдорд╛рдирджрд╛рд░ рд╣реЛрдиреЗ рдХреЗ рд▓рд┐рдП, рдореБрдЭреЗ рдпрд╣ рдирд╣реАрдВ рдорд┐рд▓рд╛ рдХрд┐ рдпрд╣ рдХреИрд╕реЗ рдорд╛рдирдХ рддрд░реАрдХреЗ рд╕реЗ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, рдФрд░ рдореБрдЭреЗ рдмрд╣реБрдд рдпрдХреАрди рдирд╣реАрдВ рд╣реИ рдХрд┐ рдЬрд┐рд╕ рдкреНрд░рд╛рд░реВрдк рдореЗрдВ рдбреЗрдЯрд╛ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ рд╡рд╣ рдирдП рд╕рдВрд╕реНрдХрд░рдгреЛрдВ рдореЗрдВ рдирд╣реАрдВ рдмрджрд▓реЗрдЧрд╛ред