Home > Software design >  How to fix the data filter problem on onChange event in react.js
How to fix the data filter problem on onChange event in react.js

Time:03-21

I have a function that filters out the data onChange events. It working fine as far as the filtration goes, But the issue is with the onChange event and setState

I'm using React Select to give the value onChange:

<Select
  id="status"
  isClearable={false}
  options={statusOptions}
  defaultValue={statusOptions[0]}
  onChange={(choice) => handleStatusFilter(choice.value)}
/>

Here the statusOptions are :

const statusOptions = [
  { value: '', label: 'Clear' },
  { value: 'draft', label: 'Draft' },
  { value: 'ready', label: 'Ready' },
  { value: 'expired', label: 'Expired' },
]

Now onChange event I'm calling the handleStatusFilter :

// state
const [status, setStatus] = useState('')

// ** handleStatusFilter
// ** Function to handle status filter
const handleStatusFilter = (value) => {
  let updatedData = []
  const dataToFilter = () => {
    if (title.length || type.length || createdAt.length || createdBy.length || status.length) {
      return filteredData
    } else {
      return results
    }
  }

  setStatus(value)
  if (value.length) {
    updatedData = dataToFilter().filter((item) => {
      const startsWith = item.status.toLowerCase().startsWith(value.toLowerCase())
      const includes = item.status.toLowerCase().includes(value.toLowerCase())

      if (startsWith) {
        return startsWith
      } else if (!startsWith && includes) {
        return includes
      } else return null
    })
    setFilteredData([...updatedData])
    setStatus(value)
  }
}

So it works the first time when the user selects any option, but not on changing his selection after that. For example; data gets filtered when the user selects the draft option. But when directly he goes from draft to ready it doesn't work, and if the user clears the state hitting the Clear option from statusOptions, and then the user selects ready then data gets filtered with this value properly.

I'm assuming there's should be a way to clear the value onChange instead of Clearing manually selecting the empty string. So how to counter this problem, is there any better approach to follow, instead of the setState method.

CodePudding user response:

The problem is more or less with this condition here:

  const dataToFilter = () => {
    if (title.length || type.length || createdAt.length || createdBy.length || status.length) {
      return filteredData
    } else {
      return results
    }
  }

Probably it returns results on the first selection because all values in the condition are falsy. For sure status.length is 0 and therefore falsy. From then on it allways returns filteredData, since status.length is truthy. Obviosly the filtered values do not include the other values anymore. So whatever you select, you will allways filter the filteredData again.

Instead you have to filter the original value results on each selection.

     updatedData = results.filter( // here use results instead of filtered values.
(item) => {
          const startsWith = item.status.toLowerCase().startsWith(value.toLowerCase())
          const includes = item.status.toLowerCase().includes(value.toLowerCase())
    
/** besides that, this can be simplified
          if (startsWith) {
            return startsWith
          } else if (!startsWith && includes) {
            return includes
          } else return null
        })**/
    return startsWith || includes

Edit1: What I said above is not wrong, but it does not consider the other filters. So in general you are restricting your results so that they can not be filtered any further. Instead, you have to apply all the filters in the same filter function, to filter down the values. Here is a codesandbox with a full example.

I used a useEffect for that and a simple html select for demonstration. But you can easiely apply that to your code.

  • Related