React中能否在对象类型Prop中传递回调函数?求助报错解决
问题:在对象类型Prop中传递回调函数时触发TypeError错误
我自定义了一个DataTable组件,通过columns、data和actions三个Prop传参,其中actions是包含回调函数handler的对象数组。但点击操作按钮时,控制台抛出TypeError: element.handler is not a function错误。
原DataTable组件代码
const DataTable = ({ columns, data, actions }) => { return <> <TableContainer> <Table sx={{ minWidth: 650 }} aria-label="simple table"> <TableHead> <TableRow> <TableCell>#</TableCell> { columns.map((item) => { return (<TableCell key={item.key}>{item.label}</TableCell>); }) } { actions && <TableCell>Actions</TableCell> } </TableRow> </TableHead> <TableBody> {data.map((row, index) => ( <TableRow key={row.id} sx={{ "&:last-child td, &:last-child th": { border: 0 } }} > <TableCell> {index + 1} </TableCell> { columns.map(item => { return (<TableCell key={item.key}>{row[item.key] ? row[item.key] : ''}</TableCell>); }) } <TableCell> { actions.map((element) => { return (<React.Fragment key={element.label}><span onClick={(row) => {element.handler(row.id)}}>{element.icon}</span></React.Fragment>) }) } </TableCell> </TableRow> ))} </TableBody> </Table> <Pagination count={1} /> </TableContainer> </> } export default DataTable;
原组件使用代码
const [data, setData] = useState([]); const columns = [ { key: "provider", label: "Provider", }, { key: "phone_number", label: "Phone Number", }, { key: "status", label: "Status", }, ]; const actions = [ { icon: <VisibilityIcon sx={{ color: '#1976d2', cursor: 'pointer' }} />, label: 'View', handler: '' }, { icon: <DeleteIcon sx={{ color: '#1976d2', marginLeft: '4px', cursor: 'pointer' }} />, label: 'Delete', handler: deleteHandler } ]; // Fetching data from api const deleteHandler = async (id) => { // Calling delete api } return <> <Card> <CardContent> <DataTable columns={columns} data={data} actions={actions} /> </CardContent> </Card></>;
问题原因与解决方案
核心原因
actions数组中第一个元素的handler被赋值为空字符串'',这不是函数类型,点击时调用element.handler(row.id)自然会触发类型错误。此外还有两个细节问题:
onClick回调错误地将事件对象命名为row,覆盖了外层的行数据变量- 未对
actions的存在性和handler的类型做前置校验
修复步骤
- 修正无效handler值:将不需要执行逻辑的
handler设为空函数() => {},禁止使用字符串或其他非函数类型 - 添加类型校验:调用
handler前先判断其是否为函数,避免非函数值触发报错 - 修正事件参数命名:将
onClick的参数改为e(或直接忽略),使用外层的row变量获取行ID
修改后的组件使用代码
const [data, setData] = useState([]); const columns = [ { key: "provider", label: "Provider", }, { key: "phone_number", label: "Phone Number", }, { key: "status", label: "Status", }, ]; // 修正View操作的handler为无操作函数 const actions = [ { icon: <VisibilityIcon sx={{ color: '#1976d2', cursor: 'pointer' }} />, label: 'View', handler: () => {} }, { icon: <DeleteIcon sx={{ color: '#1976d2', marginLeft: '4px', cursor: 'pointer' }} />, label: 'Delete', handler: deleteHandler } ]; const deleteHandler = async (id) => { // 调用删除API的逻辑 } return ( <Card> <CardContent> <DataTable columns={columns} data={data} actions={actions} /> </CardContent> </Card> );
修改后的DataTable组件代码
const DataTable = ({ columns, data, actions }) => { return ( <TableContainer> <Table sx={{ minWidth: 650 }} aria-label="simple table"> <TableHead> <TableRow> <TableCell>#</TableCell> {columns.map((item) => ( <TableCell key={item.key}>{item.label}</TableCell> ))} {actions && <TableCell>Actions</TableCell>} </TableRow> </TableHead> <TableBody> {data.map((row, index) => ( <TableRow key={row.id} sx={{ "&:last-child td, &:last-child th": { border: 0 } }} > <TableCell>{index + 1}</TableCell> {columns.map(item => ( <TableCell key={item.key}>{row[item.key] || ''}</TableCell> ))} {actions && ( <TableCell> {actions.map((element) => ( <React.Fragment key={element.label}> <span onClick={() => { // 先校验handler类型,再执行 typeof element.handler === 'function' && element.handler(row.id) }} > {element.icon} </span> </React.Fragment> ))} </TableCell> )} </TableRow> ))} </TableBody> </Table> <Pagination count={1} /> </TableContainer> ) } export default DataTable;
内容的提问来源于stack exchange,提问作者Ninja Turtle
相关产品推荐
相关产品推荐

