skip to Main Content

I want to render a list and want to make each item clickable.

But when I create a function inside renderItem then on every rerender its recreate. So how I can use clickhandler and memo on this code correctly ?

import { mockAvailableCarsData } from '../../utils/mockData';
import TableDashboardBox from '../TableDashboardBox/TableDashboardBox';
import { IAvailableCarsData } from './types';

const renderItem = (el: IAvailableCarsData) => {
 const navigate = useNavigate();
  return (
    <>
      <tr onClick={() => navigate(`/cars/${el.id}`}  className="meetings-tr">
        <td>{el.car} - {el.mark}</td>
        <td>{el.fuel}</td>
      </tr>
    </>
  )
};

function AvailableCars() {
  return (
    <TableDashboardBox<IAvailableCarsData>
      data={mockAvailableCarsData}
      headerData={['Auto', 'Reichweite']}
      renderItem={renderItem}
      keyExtractor={({id}) => id.toString()}
      title="Available"
      moreLinkURL="/cars"
      createButtonText={null}
      classNameBox="w-100 mt-24 av-cars-box"
    />
  )
}

export default AvailableCars

2

Answers


  1. import { memo, useCallback } from 'react';
    import { useNavigate } from 'react-router-dom';
    import { mockAvailableCarsData } from '../../utils/mockData';
    import TableDashboardBox from '../TableDashboardBox/TableDashboardBox';
    import { IAvailableCarsData } from './types';
    
    const RenderItem = memo(({ el }: { el: IAvailableCarsData }) => {
      const navigate = useNavigate();
      const handleClick = useCallback(() => {
        navigate(`/cars/${el.id}`);
      }, [navigate, el.id]);
    
      return (
        <tr onClick={handleClick} className="meetings-tr">
          <td>{el.car} - {el.mark}</td>
          <td>{el.fuel}</td>
        </tr>
      );
    });
    
    function AvailableCars() {
      return (
        <TableDashboardBox<IAvailableCarsData>
          data={mockAvailableCarsData}
          headerData={['Auto', 'Reichweite']}
          renderItem={(el) => <RenderItem key={el.id} el={el} />}
          keyExtractor={({ id }) => id.toString()}
          title="Available"
          moreLinkURL="/cars"
          createButtonText={null}
          classNameBox="w-100 mt-24 av-cars-box"
        />
      );
    }
    
    export default AvailableCars;
    

    Try this code. If you have any problem, feel free to reach out me.

    Login or Signup to reply.
  2. Here is an annotated code.
    in short

    • create component to render list item and wrap it memo()
    • move headers and keyExtractor outside of the component
    • wrap renderItem to useCallback() to prevent rerenders
    import { memo, useCallback } from 'react';
    import { mockAvailableCarsData } from '../../utils/mockData';
    import TableDashboardBox from '../TableDashboardBox/TableDashboardBox';
    import { IAvailableCarsData } from './types';
    
    // when using memo we don't need to wrap navigate into useCallback hook.
    const CarsData = memo(({ el }: { el: IAvailableCarsData }) => {
      const navigate = useNavigate();
      return (
        <tr onClick={() => navigate(`/cars/${el.id}`)} className="meetings-tr">
          <td>
            {el.car} - {el.mark}
          </td>
          <td>{el.fuel}</td>
        </tr>
      );
    });
    
    // move keyExtractor and headerData outside of the component to prevent unnecessary rerenders
    const keyExtractor = ({ id }: IAvailableCarsData) => id.toString();
    const headerData = ['Auto', 'Reichweite'];
    
    function AvailableCars() {
      // wrap renderItem to useCallback to make sure it is wont change on each rerender.
      const renderItem = useCallback(
        (el: IAvailableCarsData) => <CarsData key={el.id} el={el} />,
        [],
      );
      return (
        <TableDashboardBox<IAvailableCarsData>
          data={mockAvailableCarsData}
          headerData={headerData}
          renderItem={renderItem}
          keyExtractor={keyExtractor}
          title="Available"
          moreLinkURL="/cars"
          createButtonText={null}
          classNameBox="w-100 mt-24 av-cars-box"
        />
      );
    }
    
    export default AvailableCars;
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search