skip to Main Content

I am trying to prevent re-render my child component <FyTable />

I have parent component called <TableCustomer />

this is parent component looks like

import {
  columnDef_FilterCustomer,
  columnType_FilterCustomer,
} from "./ColumnDef";
import { useDebounce } from "@uidotdev/usehooks";

const TableCustomer = (props) => { 
  const { resetRowSelection = false } = props;

  const [filterData, setFilterData] = useState([]);     //textfield filter values
  const debounceFilter = useDebounce(filterData, 500);  //debounce, to avoid calling useQuery for every keypress
  const [tbData, setTbData] = useState({});             //useQuery result will be set

  const handleSelectedRow = useCallback((tbCustomerSeletedRow) => {
      console.log(tbCustomerSeletedRow)  //print selected row from child component
  }, [debounceFilter,columnDef_FilterCustomer, 
  tbData,columnType_FilterCustomer,resetRowSelection]);

  const handleFilter = (event) => {
       // logic...
      setFilterData(arrayValue)
  }

  // calling useQuery debounceFilter as a parameter
  const {
    isSuccess: isSuccess_get_filterCustomer,
    data: data_get_filterCustomer,
    isError: isError_get_filterCustomer,
    error: error_get_filterCustomer,
    isPending: isPending_get_filterCustomer,
    fetchStatus: fetchStatus_get_filterCustomer,

  } = query_Get_FilterCustomer(debounceFilter);

  useEffect(() => {

    if (isSuccess_get_filterCustomer) {
      setTbData(data_get_filterCustomer?.data);
    }
    if (isError_get_filterCustomer) {
      console.log(error_get_filterCustomer);
    }
  }, [isSuccess_get_filterCustomer,data_get_filterCustomer,
    isError_get_filterCustomer,error_get_filterCustomer]);

  return (
  <>
     {/* Filter Fields */}
        <TextField
          variant="filled"
          label="Customer No"
          name="custNo"
          onChange={(event) => handleFilter(event)}
        />

        <TextField
          variant="filled"
          label="Customer Name"
          name="custName"
          onChange={(event) => handleFilter(event)}
        />

        <TextField
          variant="filled"
          label="Phone No"
          name="phoneNo"
          onChange={(event) => handleFilter(event)}
        />

    {/* Customer Table */}

      <FyTable
        columnDef={columnDef_FilterCustomer}
        data={tbData}
        columnDataType={columnType_FilterCustomer}
        resetRowSelection={resetRowSelection}
        handleSelectedRow={handleSelectedRow}
      />

  </>
)}

export default TableCustomer

My child table component export with memo

export default React.memo(FyTable);

everything working fine, without an error, But When I type text on any filter TextFields, it’s totally lagging, each key press calling child components

I agree if parent components any changes on state values (here filterData onChange on TextFields), this will re-render child component

To avoid re-render, I tried to use useCallback hooks and memoize the child component. still it re-render like a hell…

What am i missing?. please give me some explanation

2

Answers


  1. Chosen as BEST ANSWER

    thanks to @AbdullahCh, who mentioned in the comments about const MemoizedComponent = memo(SomeComponent, arePropsEqual?)

    I followed this react.dev/memoizedcomponent

    In my ChildComponent, I compare the current props with prevProps. Then it works smoothly

    so my child component will be looks like this

    const ChildComponent = (props) => {
      //logic..
      return(
        <>
        </>
      )
    }
    
    function propsAreEqual(prevProps, nextProps){
      console.log('🚀 Props are equal Triggered')
      //console.log(prevProps)
      //console.log(nextProps)
    
      /**
       * check prevProps and nextProps(current props) are equal
       * if all prevProps and nextProps are totally equal then return 'true'. so IT WILL NOT RE-RENDER
       * if prevProps and nextProps are not equal return 'false', then component will re-render
       */
      let isSamePropsStatus = true 
    
      if(JSON.stringify(prevProps?.data) === JSON.stringify(nextProps?.data)) { isSamePropsStatus= true} else {isSamePropsStatus=false}
      
      // compare rest of all props, based on your priority 
    
      return isSamePropsStatus
    }
    
    export default React.memo(ChildComponent, propsAreEqual); //wrap the component and props comparison function
    

  2. Write a arePropsEqual func and decide when to re-render the child component:-

    const MemoizedComponent = memo(ChildComponent, arePropsEqual)
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search