iterate through properties of multiple objects

So you want to get the state from two selectors and do some work, then return the result? This is the perfect type of problem for reselect. Reselect is a helper that allows you to memoize expensive calculations regarding state selectors.

https://github.com/reduxjs/reselect

Heres what that could look like for you.

$ yarn add reselect

import React from 'react';
import { useSelector } from 'react-redux';
import { createSelector } from 'reselect';

const filterArraySelector = (state) => state.filterArray;
const doctorsSelector = (state) => state.doctors;

const filteredDoctorsSelector = createSelector(doctorsSelector, filterArraySelector, (filterArray, doctors) => {
  return doctors.filter((doctor) => {
    return filterArray.all((key) => {
      // Do some comparison here, return true if you want to include the doctor in the results
      return doctor[key] !== undefined;
    });
  });
});

const Results = () => {
  const filteredDoctors = useSelector(filteredDoctorsSelector);

  return filteredDoctors.map((doctor) => <span>{doctor}</span>);
};

Alternative Option

Instead of using createSelector to memoize the filtering, you can simply filter the doctors every time you render. Like this:

const Results = () => {
  const filterArray = useSelector((state) => state.filterArray);
  const doctors = useSelector((state) => state.doctors);

  const filteredDoctors = useMemo(
    () =>
      doctors.filter((doctor) => {
        return filterArray.all((key) => {
          // Do some comparison here, return true if you want to return the doctor
          return doctor[key] !== undefined;
        });
      }),
    [doctors, filterArray]
  );

  return filteredDoctors.map((doctor) => <span>{doctor}</span>);
};

Update:

Given a filterArray of values like this:

const filterArray = ['Female', 'English'];

We can update the filter function to test the Objects values against the filterArray values. If any of the attribute values match the filterArray values, then we can include the doctor in the resulting filteredDoctors list.

const Results = () => {
  const filterArray = useSelector((state) => state.filterArray);
  const doctors = useSelector((state) => state.doctors);

  const filteredDoctors = useMemo(() => {
    return doctors.filter((doctor) => {
      return filterArray.some((filter) => {
        return Object.values(doctor).some((value) => value === filter);
      });
    });
  }, [doctors, filterArray]);

  return filteredDoctors.map((doctor) => <span>{doctor}</span>);
};

Update:

After discussion in chat:

const Results = () => {
  const filterArray = useSelector((state) => state.filterArray);
  const doctors = useSelector((state) => state.doctors);

  const filteredDoctors = useMemo(() => {
    return doctors.filter((doctor) => {
      return filterArray.some((filter) => {
        return Object.values(doctor).some((value) => {
          // If the attribute value is an array
          if (Array.isArray(value)) {
            return value.some((value) => value === filter);
          }
          // If the attribute value is an object, get the values from the object
          if (typeof value === 'object') {
            return Object.values(value).some((value) => value === filter);
          }
          // By default, expect the value to be a string
          return value === filter;
        });
      });
    });
  }, [doctors, filterArray]);

  return filteredDoctors.map((doctor) => <span>{doctor}</span>);
};

CLICK HERE to find out more related problems solutions.

Leave a Comment

Your email address will not be published.

Scroll to Top