Home > Net >  Returning a filtered nested array inside an array of objects in React
Returning a filtered nested array inside an array of objects in React

Time:11-15

I have a piece of data in a 'serviceProviders' state which holds data as so:

[
  {
    "id": 1,
    "name": "Mental Wellness",
    "services": [
      {
        "name": "Footcare & more",
        "serviceType": "Footcare",
        "location": {
          "lat": 43.65040363335024,
          "lng": -79.38396226829892
        }
      },
      {
        "name": "Brain Wellnes",
        "serviceType": "Mental",
        "location": {
          "lat": 43.655931348619475,
          "lng": -79.37928150811159
        }
      },
      {
        "name": "Physical service",
        "serviceType": "Physical",
        "location": {
          "lat": 43.70312522921196,
          "lng": -79.34393786935266
        }
      }
    ]
  }
]

I want to write a function which filters the nested array(services) based on matching serviceType to some other variable and returns the whole object with the updated services array and sets a new state.

something along these lines:

  const filter = () => {
    serviceProviders.map((provider) => {
      const filtered = provider.services.filter((service) => service.serviceType === 'Mental')
      setServiceProviders(serviceProviders => [...serviceProviders, serviceProviders.services = filtered ])
    })
  }

should return:

[
  {
    "id": 1,
    "name": "Mental Wellness",
    "services": [
      {
        "name": "Brain Wellnes",
        "serviceType": "Mental",
        "location": {
          "lat": 43.655931348619475,
          "lng": -79.37928150811159
       }
    ]
  }
]

any help would be much appreciated. thank you.

CodePudding user response:

First, I'd suggest using the useMemo hook to create transformed sets so you don't mutate your original data.

To filter down the services to ones with the selected serviceType or as per your comment...

if there are no matches then return the original services array

try this...

const [ serviceProviders, setServiceProviders ] = useState([
  // your array data here
])
const [ serviceType, setServiceType ] = useState("Mental")

const providers = useMemo(() => {
  const predicate = svc => svc.serviceType === serviceType

  return serviceProviders.map(sp => ({
    ...sp,
    services: sp.services.some(predicate) // are there matches
      ? sp.services.filter(predicate) // yes, use the filtered array
      : [...sp.services] // no, clone the original array
  }))
}, [ serviceProviders, serviceType ]) // dependencies

This memoized value will only recompute if either of the dependencies change.


If you wanted to completely filter out top-level objects with no matches, try this instead

return serviceProviders.filter(sp => sp.services.some(predicate))
  .map(sp => ({
    ...sp,
    services: sp.services.filter(predicate)
  }))
  • Related