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 and here is the working demo
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
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
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
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