You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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 Props as the state type, and incorrectly includes selectedIndex in props (it should be internal state).
  • Incorrect State Property Name: In functional components, setSelectedIndex is a state setter function, but in class components, your state only needs to store the value selectedIndex—there's no setSelectedIndex state property.
  • Wrong setState Calls: You tried to update setSelectedIndex in componentDidMount and your click handler, but you should be updating the selectedIndex state directly.
  • Missing UI Element: You dropped the branding section 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?

  1. Proper Type Definitions:
    • Created a separate State interface for internal state (only selectedIndex).
    • Extended Props with WithStyles<typeof styles> to get proper TypeScript support for Material-UI classes.
  2. Fixed State Handling: Initialized state correctly and updated selectedIndex directly in setState calls (no more references to non-existent setSelectedIndex state property).
  3. Restored Missing UI: Added back the branding section that was omitted from your initial class component.
  4. Fixed Click Handlers: Passed the correct index value to handleClickDashboard for each list item, so selecting different menu items updates the state as expected.
  5. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 09:10:33