React自定义日视图调度器轮播失效,请求代码排查
问题描述
我正在尝试实现一个React自定义日视图调度器轮播,但当前功能无法正常运行。点击上一页或下一页按钮时无任何响应,虽然打印refs显示其已正常更新,但滚动逻辑似乎未生效。请问这段代码存在什么问题,导致无法达到预期效果?我哪里操作出错了?我仅希望点击前后按钮时,refs能相应触发滚动逻辑。
原代码
const DailyTable = () => { let time = [ "12:00 AM", "01:00 AM", "02:00 AM", "03:00 AM", "04:00 AM", "05:00 AM", "06:00 AM", "07:00 AM", "08:00 AM", "09:00 AM", "10:00 AM", "11:00 AM", "12:00 PM", "01:00 PM", "02:00 PM", "03:00 PM", "04:00 PM", "05:00 PM", "06:00 PM", "07:00 PM", "08:00 PM", "09:00 PM", "10:00 PM", "11:00 PM", ]; const boxRef = useRef(null); const boxRef2 = useRef([]); const addToRef = (el) => { boxRef2.current = []; if (boxRef2 && !boxRef2.current.includes(el)) { boxRef2.current.push(el); } }; const previous = () => { boxRef.current.scrollLeft += -100; for (let index = 0; index < boxRef2.current.length; index++) { boxRef2.current[index].scrollLeft += -100; } }; const next = () => { console.log(boxRef2.current.length); boxRef.current.scrollLeft += 100; for (let index = 0; index < boxRef2.current.length; index++) { console.log(boxRef2.current[index]); boxRef2.current[index].scrollLeft += 100; } }; return ( <Fragment> <Box sx={{ p: 3, borderRadius: "10px" }}> <TableContainer component={Paper} sx={{ width: "calc(100% - 20px)", overflow: "hidden", borderBottomLeftRadius: 15, bottom: 0, }} > <Table> <TableHead> <TableRow> <TableCell align="center" sx={{ width: "150px", fontWeight: 700 }} > Worker </TableCell> <Box sx={{ position: "relative", display: "flex", alignItems: "center", borderBottom: "1px solid rgba(224, 224, 224, 1)", }} > <span style={{ cursor: "pointer", marginTop: 7 }} onClick={previous} > {" "} <FaArrowLeft /> </span> <Box ref={boxRef} sx={{ width: "calc(100% - 20px)", overflow: "hidden" }} > {time.map((item, index) => { return ( <TableCell key={index} id={index} sx={{ minWidth: 20, borderBottom: "none" }} > {item} </TableCell> ); })} </Box> <span style={{ marginTop: 7, cursor: "pointer", position: "absolute", right: 10, }} onClick={next} > {" "} <FaArrowRight /> </span> </Box> </TableRow> </TableHead> {workers.map((item, index) => { return ( <TableBody> <Box ref={addToRef} sx={{ width: "calc(100% - 20px)", overflow: "hidden", position: "relative", top: 1, }} > {time.map((timeV, index) => { return ( <TableCell key={index} id={index} align="left" sx={{ verticalAlign: "middle", height: 77, minWidth: 100, p: 0.7, borderRight: "1px solid rgba(224,224,224,1)", }} > {item.assignWorks.map((work, index) => { var mStart = moment(work.assignDetails.startTime); var roundUpStartTime = mStart.minute() || mStart.second() || mStart.millisecond() ? mStart.add(1, "hour").startOf("hour") : mStart.startOf("hour"); var width = work.assignDetails.timeDiff == 0 ? 106 : work.assignDetails.timeDiff * 106; let count = 0; if ( roundUpStartTime.format("hh:mm A") === timeV ) { count += 1; return ( <Box key={index}> {(work.assignDetails.status === "pending" || work.assignDetails.status === "request") && ( <Chip onClick={() => { setSelectedJob(work._id); setShowEditJob(true); }} label={work.name} sx={{ mb: 2, borderRadius: "5px", fontWeight: 600, backgroundColor: `${colors.chip.lightBlue}`, color: `${colors.chip.Blue}`, width: width - 12, }} /> )} </Box> ) } })} </TableCell> ); })} </Box> </TableBody> ); })} </Table> </TableContainer> </Box> </Fragment> ); };
问题分析与解决方案
1. Ref收集逻辑错误
addToRef函数每次调用都会清空boxRef2.current = [],导致最终boxRef2.current中只会保留最后一个worker对应的Box元素,前面的所有ref都会丢失。修改方式:
const addToRef = (el) => { if (el && !boxRef2.current.includes(el)) { boxRef2.current.push(el); } }; // 组件卸载时清理ref,避免内存泄漏 useEffect(() => { return () => { boxRef2.current = []; }; }, []);
2. 滚动容器样式错误
所有需要滚动的容器设置了overflow: hidden,这会阻止容器滚动,必须改为overflow-x: scroll(只允许水平滚动):
// 表头的滚动容器 <Box ref={boxRef} sx={{ width: "calc(100% - 20px)", overflowX: "scroll" }} > {/* 时间列内容 */} </Box> // 每个worker的滚动容器 <Box ref={addToRef} sx={{ width: "calc(100% - 20px)", overflowX: "scroll", position: "relative", top: 1, }} > {/* 任务列内容 */} </Box>
3. Table结构不符合规范
在workers.map中直接返回<TableBody>违反了Table组件的结构规范:一个<Table>应包含一个<TableBody>,且<TableRow>的子元素必须是<TableCell>。正确结构调整如下:
<Table> <TableHead> {/* 原有表头代码 */} </TableHead> <TableBody> {workers.map((item, index) => { return ( <TableRow key={index}> <TableCell align="center" sx={{ width: "150px" }}> {item.name} {/* 显示worker名称 */} </TableCell> <TableCell sx={{ p: 0 }}> <Box ref={addToRef} sx={{ width: "100%", overflowX: "scroll", }} > {/* 原有时间列与任务内容 */} </Box> </TableCell> </TableRow> ); })} </TableBody> </Table>
4. Moment对象可变问题
直接修改moment原对象会导致时间计算异常,需要先克隆对象:
var mStart = moment(work.assignDetails.startTime).clone(); var roundUpStartTime = mStart.minute() || mStart.second() || mStart.millisecond() ? mStart.add(1, "hour").startOf("hour") : mStart.startOf("hour");
内容的提问来源于stack exchange,提问作者Muhammad Abdullah
相关产品推荐
相关产品推荐

