How Would you make this React code with dynamic filtering more optimized
Tags: react, performance, webdev, typescript
Published: 2022-06-08 05:28:23

I was given a task of optimizing our dashboards performance this week. And to be honest I wasn't really sure what is it means by optimization. On googling I found that one way to optimize is reducing unnecessary re-render and aviding unnecessary API calls.

so I set the my goals like this:

- To have Fewer Render hence better performance (possibly by introducing useRef instead of useState if possible)

- Eliminating Unnecessary API calls (when applying the same filter or when clicking reset again and again shouldn't trigger an API call)

- Right way to use useReducer and check for anti-patterns in my 
custom hook

And I came up with the [minimal, workable example](https://codesandbox.io/s/mcu59v) and here is the [working demo](https://mcu59v.csb.app/)

I was only half successful in acheiving my optimization:

- Once I apply filter and then apply it again it doesn't call the mock api
- Once I change resultLimit to same value it doesn't call api
Here is how I did it

```tsx
    const [page,setPage] = useState(1)//current page filter
    const [resultLimit,setResultLimit] = useState(10) //result limit filter,currently not implemented
    const [totalCount,setTotalCount] = useState(0) // total result count filter
    const [filters,setFilters] =useState<IFilterBugData>({
        platform:[],
        rootCause: [],
        reportedBy: [],
        assignedTo: [],
        status: [],
        defectCategory: [],
        severity: [],
        priority: [],
    })//filter options

    const [bugsData,setBugsData] = useState<IBug[]>([]) //bugs result

    const handleFilterDispatch = (state:IKeyValue[],payload:IFilterPayload) => {
        let _temp = [...state]
        switch(payload.action){
            case 'add':
                return _temp
            case 'reset':
                return []
            default:
                return _temp
        }
    }// use reducer for handling function temp filter state

    // const filterState = useRef<IKeyValue[]>([])
    const [filterState,filterDispatch] = useReducer(handleFilterDispatch,[])//temp filter state
    const [finalFilterState,setFinalFiterState] = useState<IKeyValue[]>([])//input filter state
```

```tsx
    const memoizedInput:IInputBugData = useMemo(() => {
        return {
            filters:finalFilterState,
            page,
            resultLimit
        }
    },[finalFilterState,page,resultLimit])

    const getBugsData = useCallback(() =>   {
        console.log('inside memoized callback',memoizedInput)
        
        return getBugs(memoizedInput)
    }, [memoizedInput])
```
and calling the memoized function `getBugsData` in useEffect although I have doubt that `memoizedInput` is not necessary here

```tsx
    useEffect(() => {
        console.log('rendering dataaaaaa')
        let {resultCount,currentPage,bugs,filters} = getBugsData()
        setBugsData(bugs)
        setFilters({...filters})
        setPage(currentPage)
        setTotalCount(resultCount)
    },[getBugsData])
```
But What it failed to do is 

- It stills call api when I deselect and select the same option resulting in same filterstate
- clicking reset always calls api (even if there is no filter applied)
- even if I haven't changed my filters when I click apply it re-renders (only once)

so my question is how would you guys do it differently. 

_**Note**: you guys can also point out the anti-patterns I have done, as I am not sure if I am doing custom hooks or useReducer/useCallback/useMemo the correct way_