1

I have a table that displays users List. It fetches the data from my backend server. when i try to fetch data its takes (4 render ) to Get the actual data. How can i use useEffect and useMemo to avoid re-render. iam using a custom hook to fetch the data. The code is down below.

Custom Hook

export const useFetch = url => {
  const [data, setData] = useState([])
  const [error, setError] = useState()
  const [loading, setLoading] = useState(false)

  useEffect(() => {
    const fetchData = async () => {
      setLoading(true)
      await axios
        .get(url)
        .then(response => setData(response.data))
        .catch(setError)
        .finally(() => setLoading(false))
    }
    fetchData()
    console.log(data)
    // console.log('Use Fetch Hook')
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [url])

  return {data, error, loading}
}

Users List Component .jsx

import React from 'react'

import Card from '../../UI/Card'
import classes from './Users.module.css'
import {useFetch} from '../../../hooks/useFetch'
import {Typography} from '@mui/material'
import DataTable from '../../UI/DataTable'

const Users = props => {
  const url = 'http://localhost:3001/auth/getUsers'

  // Fetch API
  const {data, error, loading} = useFetch(url)
  console.log(data)

  let columns = []
  if (data === undefined || data === null || data.length === 0) {
  } else {
    columns = Object.keys(data[0]).map(key => {
      const capitalize = key.toLocaleUpperCase()
      return {Header: capitalize, accessor: key}
    })
  }
  //  useMemo(()=>{},[])
  return (
    <>
      <Card className={classes.users}>
        <div>
          <h1>User Details</h1>
        </div>

        {loading && (
          <Typography variant="h5" color="secondary">
            Loading...
          </Typography>
        )}
        {error && <p>{error.message}</p>}
        {data && <DataTable columns={columns} data={data}></DataTable>}
      </Card>
    </>
  )
}

export default Users

DataTable.jsx Is there any ways to make the table editable only when selecting the row

import classes from './DataTable.module.css'
//import EditableCell from './EditCell'

//React Table Library
import {
  useTable,
  useSortBy,
  useGlobalFilter,
  usePagination,
  useRowSelect,
} from 'react-table'

// UI elements
import {Checkbox} from './CheckBox'
import GlobalFilter from './GlobalFilter'
//import {useState} from 'react'

const DataTable = ({columns, data}) => {
  // const defaultColumn = {
  //   Cell: EditableCell,
  // }
  console.log('render')

  const tableHooks = hooks => {
    hooks.visibleColumns.push(columns => [
      ...columns,
      {
        id: 'Edit',
        Header: 'Edit',
        Cell: ({row}) => (
          <button onClick={() => handleEdit(row.original)}>Edit</button>
        ),
      },
    ])
  }
  const tableInstance = useTable(
    {data, columns},
    useGlobalFilter,
    tableHooks,
    useSortBy,
    usePagination,
    useRowSelect,
    hooks => {
      hooks.visibleColumns.push(columns => {
        return [
          {
            id: 'selection',
            Header: ({getToggleAllRowsSelectedProps}) => (
              <Checkbox {...getToggleAllRowsSelectedProps()} />
            ),
            Cell: ({row}) => (
              <Checkbox
                onClick={() => {
                  handleDelete(row.original)
                }}
                {...row.getToggleRowSelectedProps()}
              />
            ),
          },

          ...columns,
        ]
      })
    },
  )

  const {
    getTableProps,
    getTableBodyProps,
    headerGroups,
    // rows,
    page,
    // nextPage,
    // previousPage,
    prepareRow,
    // selectedFlatRows,
    state,
    setGlobalFilter,
  } = tableInstance
  const {globalFilter} = state

  const handleEdit = row => {
    console.log(row)
  }
  const handleDelete = row => {
    // const userId = row.original.username
    // axios({
    //   method: 'DELETE',
    //   url: 'http://localhost:3001/auth/delete/' + userId,
    //   withCredentials: true,
    //   credentials: 'include',
    // })
    //   .then(response => response.json())
    //   .then(data => {
    //     console.log(data)
    //   })
    //   .catch(error => {
    //     console.log(error)
    //   })
    // console.log(selectedFlatRows)
    // setedit(prev => !prev)
  }
  return (
    <>
      <GlobalFilter filter={globalFilter} setFilter={setGlobalFilter} />
      <div className={classes.box}>
        <div className={classes.container}>
          <div className={classes.innerContainer}>
            <table className={classes.table} {...getTableProps()}>
              <thead>
                {headerGroups.map(headerGroup => (
                  <tr {...headerGroup.getHeaderGroupProps()}>
                    {headerGroup.headers.map(column => (
                      <th
                        className={classes.th}
                        {...column.getHeaderProps(
                          column.getSortByToggleProps(),
                        )}
                      >
                        {column.render('Header')}
                        {column.isSorted
                          ? column.isSortedDesc
                            ? ' ▼'
                            : ' ▲'
                          : ''}
                      </th>
                    ))}
                  </tr>
                ))}
              </thead>
              <tbody {...getTableBodyProps()}>
                {page.map((row, idx) => {
                  prepareRow(row)

                  return (
                    <tr {...row.getRowProps()}>
                      {row.cells.map((cell, idx) => (
                        <td {...cell.getCellProps()}>{cell.render('Cell')}</td>
                      ))}
                    </tr>
                  )
                })}
              </tbody>
            </table>
          </div>
        </div>
      </div>

      {/* {
        <>
          <button onClick={() => previousPage()}>Previous</button>
          <button onClick={() => nextPage()}>Next</button>
        </>
      } */}
    </>
  )
}

export default DataTable

Shyam
  • 21
  • 4

1 Answers1

0

In order to avoid re-renders, you could wrap a JSX component in useMemo like so:

import React, {useMemo} from 'react'
import Card from '../../UI/Card'
import classes from './Users.module.css'
import {useFetch} from '../../../hooks/useFetch'
import {Typography} from '@mui/material'
import DataTable from '../../UI/DataTable'

const Users = props => {
    const url = 'http://localhost:3001/auth/getUsers'

    // Fetch API
    const {data, error, loading} = useFetch(url)
    console.log(data)

    let columns = []
    if (data === undefined || data === null || data.length === 0) {
    } else {
        columns = Object.keys(data[0]).map(key => {
            const capitalize = key.toLocaleUpperCase()
            return {Header: capitalize, accessor: key}
        })
    }
    //  useMemo(()=>{},[])
    return (
        <>
            <Card className={classes.users}>
                <div>
                    <h1>User Details</h1>
                </div>

                {loading && (
                    <Typography variant="h5" color="secondary">
                        Loading...
                    </Typography>
                )}
                {error && <p>{error.message}</p>}
                {
                    useMemo(() => {
                        return data && (<DataTable columns={columns} data={data}></DataTable>)
                    }, [data, columns])
                }
            </Card>
        </>
    )
}

export default Users
hpertaia
  • 106
  • 6
  • 1
    hi @hpertaia i tried with your suggestion it wont work. Now it render 8 times initial loading – Shyam Aug 21 '22 at 23:53