React函数组件转类组件报错:setSelectedIndex不存在于指定类型
Fixing Your React Class Component Conversion
Let's walk through fixing your class component step by step—your error stems from mixing up state properties and incorrect setState usage, plus a few other small mismatches with the original functional component.
Key Issues in Your Current Code
- Confused Props and State Types: Your class component uses
Propsas the state type, and incorrectly includesselectedIndexin props (it should be internal state). - Incorrect State Property Name: In functional components,
setSelectedIndexis a state setter function, but in class components, your state only needs to store the valueselectedIndex—there's nosetSelectedIndexstate property. - Wrong
setStateCalls: You tried to updatesetSelectedIndexincomponentDidMountand your click handler, but you should be updating theselectedIndexstate directly. - Missing UI Element: You dropped the
brandingsection from the original component.
Corrected Class Component Code
import * as React from 'react'; import { withStyles, WithStyles } from '@material-ui/core/styles'; import Drawer from '@material-ui/core/Drawer'; import List from '@material-ui/core/List'; import Divider from '@material-ui/core/Divider'; import ListItem from '@material-ui/core/ListItem'; import ListItemIcon from '@material-ui/core/ListItemIcon'; import ListItemText from '@material-ui/core/ListItemText'; import DashboardIcon from '@material-ui/icons/Dashboard'; import BarChartIcon from '@material-ui/icons/BarChart'; import AssignmentIndIcon from '@material-ui/icons/AssignmentInd'; import { Link } from 'react-router-dom'; import './drawer.scss'; const drawerWidth = 87; const styles = { root: { display: 'flex' }, appBar: { zIndex: 2000 }, drawer: { width: drawerWidth, flexShrink: 0 }, drawerPaper: { width: drawerWidth }, content: { flexGrow: 1, padding: 3 }, toolbar: { minHeight: 64 } //补全原组件用到但未定义的样式类 }; // 正确定义Props:仅包含Material-UI注入的classes interface Props extends WithStyles<typeof styles> {} // 定义组件内部State的类型 interface State { selectedIndex: number; } class ClippedDrawer extends React.Component<Props, State> { constructor(props: Props) { super(props); // 初始化state,与原函数组件保持一致 this.state = { selectedIndex: -1 }; } public componentDidMount(): void { const path: string = window.location.pathname; let targetIndex = 1; switch (path) { case '/': targetIndex = 1; // 与原函数组件逻辑保持一致 break; default: targetIndex = 1; break; } // 更新正确的state属性 this.setState({ selectedIndex: targetIndex }); } private handleClickDashboard = ( event: React.MouseEvent<HTMLLIElement | HTMLAnchorElement | HTMLDivElement>, index: number = 0 ) => { // 直接更新selectedIndex状态 this.setState({ selectedIndex: index }); }; public render() { // 从props解构classes,从state解构selectedIndex const { classes } = this.props; const { selectedIndex } = this.state; return ( <div className={classes.root}> <Drawer className={classes.drawer} variant='permanent' classes={{ paper: classes.drawerPaper }} > <div className={classes.toolbar} /> <List> <Link to={'/'}> <ListItem button selected={selectedIndex === 0} onClick={(e) => this.handleClickDashboard(e, 0)} > <ListItemIcon> <DashboardIcon /> </ListItemIcon> <ListItemText primary='Dashboard' /> </ListItem> </Link> <Divider /> <Link to={'/'}> <ListItem button selected={selectedIndex === 2} onClick={(e) => this.handleClickDashboard(e, 2)} > <ListItemIcon> <BarChartIcon /> </ListItemIcon> <ListItemText primary='Scenario Analysis' /> </ListItem> </Link> <Divider /> <Link to={'/'}> <ListItem button selected={selectedIndex === 3} onClick={(e) => this.handleClickDashboard(e, 3)} > <ListItemIcon> <AssignmentIndIcon /> </ListItemIcon> <ListItemText primary='Admin' /> </ListItem> </Link> </List> {/* 还原原组件中丢失的branding区域 */} <div className='branding'> <p>Powered by</p> <div className='logo' /> </div> </Drawer> </div> ); } } // 保持与原组件一致的导出方式 export default withStyles(styles)(ClippedDrawer);
What Changed?
- Proper Type Definitions:
- Created a separate
Stateinterface for internal state (onlyselectedIndex). - Extended
PropswithWithStyles<typeof styles>to get proper TypeScript support for Material-UI classes.
- Created a separate
- Fixed State Handling: Initialized state correctly and updated
selectedIndexdirectly insetStatecalls (no more references to non-existentsetSelectedIndexstate property). - Restored Missing UI: Added back the
brandingsection that was omitted from your initial class component. - Fixed Click Handlers: Passed the correct index value to
handleClickDashboardfor each list item, so selecting different menu items updates the state as expected. - Added Missing Style:补全了原组件用到但未定义的
toolbar样式类,避免控制台警告。
This should resolve the TypeScript error and make your class component behave exactly like the original functional component.
内容的提问来源于stack exchange,提问作者Amen Ra
相关产品推荐
相关产品推荐

