如何使用useCallback和memo防止重新渲染

问题描述 投票:0回答:1

我正在尝试阻止重新渲染我的子组件

<FyTable />

我有一个名为

<TableCustomer />

的父组件

这是父组件的样子

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

我的子表组件使用

memo

导出

export default React.memo(FyTable);

一切正常,没有错误,但是当我在任何过滤器文本字段上键入文本时,它完全滞后,每个按键都会调用子组件

我同意如果父组件对状态值有任何更改(此处

filterData
TextFields 上的 onChange),这将重新渲染子组件

为了避免重新渲染,我尝试使用 useCallback 挂钩并记住子组件。它仍然像地狱一样重新渲染......

我错过了什么?请给我一些解释

reactjs react-hooks react-memo react-usecallback
1个回答
0
投票

感谢@AbdullahCh,他在评论中提到了

const MemoizedComponent = memo(SomeComponent, arePropsEqual?)

我遵循了这个react.dev/memoizedcomponent

在我的 ChildComponent 中,我将当前的 props 与 prevProps 进行比较。然后就可以顺利运行了

所以我的子组件将如下所示

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
© www.soinside.com 2019 - 2024. All rights reserved.