MUI X Data Grid rowMouseEnter事件失效及行内按钮样式切换问题
问题描述
- 需求:鼠标悬停在DataGrid任意行时,将“Analyze”按钮从
outlined变体切换为contained变体 - 问题:
rowMouseEnter事件无法触发,同时不清楚如何在鼠标悬停行时更新该行内的单元格 - 依赖版本:
"@mui/x-data-grid": "^5.17.25", "@mui/x-data-grid-generator": "^6.0.0", "@mui/x-data-grid-pro": "^6.0.0",
代码实现
import React, { useRef, useState, useEffect } from "react"; import { DataGrid, GridRowsProp, GridColDef } from "@mui/x-data-grid"; import Box from "@mui/material/Box"; import Button from "@mui/material/Button"; import { useTheme } from "@mui/system"; import Link from "next/link"; import TextField from "@mui/material/TextField"; import InputAdornment from "@mui/material/InputAdornment"; import SearchIcon from "@mui/icons-material/Search"; import AddIcon from "@mui/icons-material/Add"; import CircularProgress from "@mui/material/CircularProgress"; import { alpha, styled, lighten } from "@mui/material/styles"; export default function PropertiesList({ newProperties }) { const theme = useTheme(); const boxRef = useRef(null); const [searchText, setSearchText] = useState(""); const columns = getColumns(theme); function getColumns(theme) { // commented because irrelevant return [ { field: "id", headerName: "Actions", width: 150, renderCell: (params) => { return ( <Box sx={{ display: "flex", justifyContent: "space-between", width: "100%" }} > <Link href="/properties/[id]" as={`/properties/${params.row.original_doc || params.row.id}`} > <Button size="small" variant="outlined" startIcon={<CalculateIcon />} sx={{ backgroundColor: hoveredRowId === params.id ? theme.palette.success.main : "" }} > Analyze </Button> </Link> </Box> ); } } ]; } useEffect(() => { if (!boxRef.current) return; const screenHeight = window.innerHeight; boxRef.current.style.height = `${screenHeight - 120}px`; }, []); const handleRowOver = (params) => { // change the analyze button from "outlined" to "contained" when hovered. // The below console.log does not trigger. console.log(`Row ${params.id} is being hovered over`); }; return ( <Box ref={boxRef}> {!newProperties && ( <Box sx={{ height: "calc(100vh - 160px)", display: "flex", justifyContent: "center", alignItems: "center" }} > <CircularProgress size={32} /> </Box> )} {newProperties && ( <> <Box sx={{ display: "flex", justifyContent: "space-between", alignItems: "center", background: theme.palette.background.background2, marginTop: 3, // marginBottom: 1, padding: 2, border: "1px solid " + theme.palette.contrast.contrast1, borderTopLeftRadius: 8, borderTopRightRadius: 8 }} > <TextField label="Search for property" placeholder="" sx={{ marginTop: 1, marginBottom: 1 }} onChange={(event) => setSearchText(event.target.value)} InputProps={{ startAdornment: ( <InputAdornment position="start"> <SearchIcon /> </InputAdornment> ) }} /> <Link href="/properties/add"> <Button size="medium" variant="contained" sx={{ height: 50 }} startIcon={<AddIcon />} > Add Property </Button> </Link> </Box> <DataGrid rowMouseEnter={handleRowOver} sx={{ border: "1px solid " + theme.palette.contrast.contrast1, height: "calc(100vh - 280px)", background: theme.palette.background.background1, "& .MuiDataGrid-virtualScroller::-webkit-scrollbar": { height: "0.4em", width: "0.4em" }, "& .MuiDataGrid-virtualScroller::-webkit-scrollbar-track": { background: theme.palette.contrast.contrast1 }, "& .MuiDataGrid-virtualScroller::-webkit-scrollbar-thumb": { backgroundColor: theme.palette.contrast.contrast2 }, "& .MuiDataGrid-virtualScroller::-webkit-scrollbar-thumb:hover": { background: theme.palette.contrast.default }, borderTopLeftRadius: 0, borderTopRightRadius: 0, borderBottomLeftRadius: 8, borderBottomRightRadius: 8 }} rows={newProperties.filter( (row) => (row.address && row.address .toLowerCase() .includes(searchText.toLowerCase())) || (row.city && row.city.toLowerCase().includes(searchText.toLowerCase())) || (row.state && row.state.toLowerCase().includes(searchText.toLowerCase())) || (row.zip && row.zip .toString() .toLowerCase() .includes(searchText.toLowerCase())) )} columns={columns} pageSize={13} disableColumnFilter disableSelectionOnClick disableColumnSelector /> </> )} </Box> ); }
解决方案
1. 修复事件不触发问题
你混用了MUI X v5和v6版本的包,导致事件名不匹配:
- v5版本的
DataGrid行鼠标进入事件名为onRowMouseEnter(带on前缀) - v6版本的事件名为
rowMouseEnter(无on前缀)
当前你安装的@mui/x-data-grid是v5.17.25,所以需要修改事件绑定:
<DataGrid onRowMouseEnter={handleRowOver} // 其他属性保持不变 />
2. 实现按钮变体切换逻辑
步骤1:添加状态跟踪悬停行ID
在组件内部新增状态变量:
const [hoveredRowId, setHoveredRowId] = useState(null);
步骤2:完善事件处理函数
添加鼠标离开行的处理函数,清除悬停状态:
const handleRowOver = (params) => { setHoveredRowId(params.id); }; const handleRowLeave = () => { setHoveredRowId(null); };
然后在DataGrid上绑定离开事件:
<DataGrid onRowMouseEnter={handleRowOver} onRowMouseLeave={handleRowLeave} // 其他属性保持不变 />
步骤3:动态切换按钮变体
修改renderCell中的按钮组件,根据hoveredRowId切换variant和样式:
<Button size="small" variant={hoveredRowId === params.id ? "contained" : "outlined"} startIcon={<CalculateIcon />} sx={{ backgroundColor: hoveredRowId === params.id ? theme.palette.success.main : "transparent", color: hoveredRowId === params.id ? theme.palette.success.contrastText : theme.palette.success.main }} > Analyze </Button>
步骤4:修复列配置的渲染问题
当前columns定义在组件顶层,状态变化时不会重新生成列配置,需要把列配置移到组件内部,确保hoveredRowId变化时能触发单元格重渲染:
// 把columns定义移到组件内部 const columns = [ { field: "id", headerName: "Actions", width: 150, renderCell: (params) => { return ( <Box sx={{ display: "flex", justifyContent: "space-between", width: "100%" }} > <Link href="/properties/[id]" as={`/properties/${params.row.original_doc || params.row.id}`} > <Button size="small" variant={hoveredRowId === params.id ? "contained" : "outlined"} startIcon={<CalculateIcon />} sx={{ backgroundColor: hoveredRowId === params.id ? theme.palette.success.main : "transparent", color: hoveredRowId === params.id ? theme.palette.success.contrastText : theme.palette.success.main }} > Analyze </Button> </Link> </Box> ); } } ];
3. 统一MUI X版本(可选但推荐)
混用v5和v6包容易引发兼容性问题,建议统一升级到同一大版本,比如全部升级到v6:
"@mui/x-data-grid": "^6.0.0", "@mui/x-data-grid-generator": "^6.0.0", "@mui/x-data-grid-pro": "^6.0.0",
如果使用v6版本,事件名改回rowMouseEnter和rowMouseLeave即可。
内容的提问来源于stack exchange,提问作者Evan Hessler
相关产品推荐
相关产品推荐

