Clay_F
Clay_F

Reputation: 589

Redux State Using Reselect To Derive Related Data

I've been stuck on this for a while.

Here's a part of my redux-state

state: {

  teachers: [
    { teacherId: 'ttt1', teacherName: 'Susan', isCool: true, teachesAt: 'sss1'},
    { teacherId: 'ttt2', teacherName: 'Karen', isCool: false, teachesAt: 'sss2'},
    { teacherId: 'ttt3', teacherName: 'Bob', isCool: true, teachesAt: 'sss3'},
    { teacherId: 'ttt4', teacherName: 'Mike', isCool: false, teachesAt: 'sss1'},
  ],

  schools: [
    { schoolId: 'sss1', schoolName: 'Washington'},
    { schoolId: 'sss2', schoolName: 'Lincoln'},
    { schoolId: 'sss3', schoolName: 'Jefferson'},
  ],

  students: [
    { schoolIdEnrolled: 'sss1', studentName: 'Billy'},
    { schoolIdEnrolled: 'sss1', studentName: 'Steven'},
    { schoolIdEnrolled: 'sss2', studentName: 'Bobby'},
    { schoolIdEnrolled: 'sss3', studentName: 'Mikey'},
    { schoolIdEnrolled: 'sss3', studentName: 'Sally'},
    { schoolIdEnrolled: 'sss3', studentName: 'Cindy'},
    { schoolIdEnrolled: 'sss3', studentName: 'Mandy'},
  ],

  classes: [...],

}

Can anyone dream up a way so that in the render method of my React Component I can loop through my schools and calculate the number of 'coolTeachers' and 'studentCount' for each school? Is this the use-case for reselect?

My table needs to be like this:

SCHOOL______# OF COOL TEACHERS_______STUDENTS

Washington__________1_______________________2

Lincoln______________0_______________________1

Jefferson____________1_______________________4

Upvotes: 4

Views: 85

Answers (1)

Sagiv b.g
Sagiv b.g

Reputation: 31024

This is classic usecase for Array.prototype.reduce:

const state = {
  teachers: [
    { teacherId: 'ttt1', teacherName: 'Susan', isCool: true, teachesAt: 'sss1'},
    { teacherId: 'ttt2', teacherName: 'Karen', isCool: false, teachesAt: 'sss2'},
    { teacherId: 'ttt3', teacherName: 'Bob', isCool: true, teachesAt: 'sss3'},
    { teacherId: 'ttt4', teacherName: 'Mike', isCool: false, teachesAt: 'sss1'},
  ],

  schools: [
    { schoolId: 'sss1', schoolName: 'Washington'},
    { schoolId: 'sss2', schoolName: 'Lincoln'},
    { schoolId: 'sss3', schoolName: 'Jefferson'},
  ],

  students: [
    { schoolIdEnrolled: 'sss1', studentName: 'Billy'},
    { schoolIdEnrolled: 'sss1', studentName: 'Steven'},
    { schoolIdEnrolled: 'sss2', studentName: 'Bobby'},
    { schoolIdEnrolled: 'sss3', studentName: 'Mikey'},
    { schoolIdEnrolled: 'sss3', studentName: 'Sally'},
    { schoolIdEnrolled: 'sss3', studentName: 'Cindy'},
    { schoolIdEnrolled: 'sss3', studentName: 'Mandy'},
  ],
}


const teachersReducer = (teachers, id) => {
  const numOfteachers = teachers.reduce((result, current) => {
    if (current.teachesAt === id && current.isCool) {
      result++;
    }
    return result;
  }, 0);
  return numOfteachers;
}

const studentsReducer = (students, id) => {
  const numOfstudents = students.reduce((result, current) => {
    if (current.schoolIdEnrolled === id) {
      result++;
    }
    return result;
  }, 0);
  return numOfstudents;
}


const resultData = state.schools.reduce((result, currentSchool) => {
  const currentId = currentSchool.schoolId;
  const numOfTeachers = teachersReducer(state.teachers, currentId);
  const numOfStudents = studentsReducer(state.students, currentId);
  return {
    ...result, 
    [currentSchool.schoolName]: {
        ...result[currentSchool],
        numOfTeachers,
        numOfStudents
    }
  }
}, {});

console.log(resultData);

You can wrap the methods with reselect but keep in mind it will only cache the last input parameter.

Upvotes: 3

Related Questions