Material UI中如何向makeStyles嵌套样式方法传递props或判断条件
问题根因
你在makeStyles的配置对象中直接调用line(theme, isRTL)时,此处的isRTL是无赋值的自由变量,和你调用useStyles({ isRTL })传入的参数没有关联。Material UI的makeStyles要接收外部传参,需要将依赖参数的样式规则声明为接收props的函数,才能拿到外部传入的参数值。
修复方案
改造useStyles实现
无需重复定义LTR/RTL两套样式规则,直接通过传入的props.isRTL做判断即可,同时正确将isRTL传给line方法:
const line = (theme, isRTL) => { console.log('isRTL', isRTL); return { display: 'block', content: '""', height: '100%', width: 1, backgroundColor: '#A3A9AA', position: 'absolute', top: 0, bottom: 0, left: isRTL ? 26 : 'initial', right: isRTL ? 'initial' : 26, zIndex: -1, [theme.breakpoints.down('sm')]: { left: isRTL ? 13 : 'initial', right: isRTL ? 'initial' : 13, }, }; }; const useStyles = makeStyles(theme => ({ container: { paddingLeft: theme.spacing(6), paddingRight: theme.spacing(6), paddingTop: theme.spacing(4), overflowY: 'scroll', position: 'relative', scrollBehavior: 'smooth', [theme.breakpoints.down('sm')]: { paddingLeft: theme.spacing(2), paddingRight: theme.spacing(2), paddingTop: theme.spacing(4), }, }, // 合并原itemIndex和itemIndexRTL itemIndex: props => ({ width: 51, height: 51, display: 'flex', alignItems: 'center', justifyContent: 'center', borderRadius: '50%', border: '1px solid currentColor', color: theme.palette.grey[500], fontSize: '20px', backgroundColor: 'white', position: 'absolute', top: 0, left: props.isRTL ? 'initial' : 0, right: props.isRTL ? 0 : 'initial', zIndex: 1, transition: 'color 0.5s', fontFamily: theme.typography.fontFamily, [theme.breakpoints.down('sm')]: { width: 25, height: 25, fontSize: '15px', }, }), completedIndex: { color: theme.palette.primary.main, }, skippedIndex: { color: theme.palette.warning.main, backgroundColor: theme.palette.warning.extraLight, }, // 合并原item和itemRTL item: props => ({ counterIncrement: 'item', position: 'relative', paddingLeft: props.isRTL ? 'initial' : 100, paddingRight: props.isRTL ? 100 : 'initial', paddingBottom: 60, [theme.breakpoints.down('sm')]: { paddingLeft: props.isRTL ? 'initial' : 40, paddingRight: props.isRTL ? 40 : 'initial', }, '&:not(:last-child):before': { ...line(theme, props.isRTL), backgroundColor: '#A3A9AA', }, '&:not(:last-child):after': { ...line(theme, props.isRTL), backgroundColor: theme.palette.primary.main, transformOrigin: 'top', transform: 'scaleY(0)', transition: 'transform 0.4s', }, }), completedAnswer: { '&:not(:last-child):after': { transform: 'scaleY(1)', }, }, skippedAnswer: { '&:not(:last-child):after': { transform: 'scaleY(1)', backgroundColor: theme.palette.warning.main, }, }, }));
简化组件内调用
不需要再手动判断isRTL切换className,逻辑更简洁:
<div key={item.id} ref={itemRefs[index]} className={classNames(classes.item, { [classes.completedAnswer]: isCompleted, [classes.skippedAnswer]: isSkipped, })} > <span aria-hidden="true" className={classNames(classes.itemIndex, { [classes.completedIndex]: isCompleted, [classes.skippedIndex]: isSkipped, })} > {index + 1} </span> <LinearStepperItem clearAnswer={setAnswer} country={country} disableAutoScroll={() => { autoScrollConfig.enabled = false; }} item={item} itemIndex={index + 1} setAnswer={(answer, autoAcroll) => { setAnswer(answer); autoScrollConfig.enabled = autoAcroll; if (autoAcroll) scrollToNextItem(index); }} setMeta={setMeta} /> </div>
原实现方案评估
你原来的思路符合功能需求,但存在明显的冗余缺陷:重复定义了两套LTR/RTL样式规则,后续维护需要同步修改两处,容易出现不一致问题。改造后的方案减少了50%的重复代码,逻辑内聚度更高,维护成本更低。
内容的提问来源于stack exchange,提问作者Jakub
相关产品推荐
相关产品推荐

