如何使用useMemo和Effect高效地使用axios从api加载React Table数据



我有一个显示用户列表的表。它从我的后端服务器获取数据。当我尝试获取数据时,获取实际数据需要花费(4渲染(。如何使用useEffectuseMemo来避免re-render。iam使用自定义钩子来获取数据。代码在下面。

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是否有任何方法可以使表仅在选择行时可编辑

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

为了避免重新渲染,可以将JSX组件包装在useMemo中,如下所示:

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

最新更新