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

React如何将函数式组件转换为类组件?附代码示例与报错处理

React函数式组件转类组件修正指导

问题说明

正在尝试将React函数式组件转换为类组件,现有改写代码存在报错需要修正。

原始函数式组件代码

import React, { useEffect, useState } from "react"
import ReactMapGL, { Marker, Popup } from "react-map-gl"
import RsuMarker from './RsuMarker';
import mbStyle from '../styles/mb_style.json';

function Map(props) {
 const [viewport, setViewport] = useState({
latitude: 39.7392,
longitude: -104.9903,
width: 'calc(100% - 350px)',
height: '100vh',
zoom: 10
});

const [selectedRsu, setSelectedRsu] = useState(null);

const [selectedRsuCount, setSelectedRsuCount] = useState(null);

useEffect(() => {
const listener = e => {
  if (e.key === "Escape")
    setSelectedRsu(null);
};
window.addEventListener("keydown", listener);

return () => {
  window.removeEventListener("keydown", listener);
}
 }, []);

return (
  <div>
  <ReactMapGL 
    {...viewport} 
    mapboxApiAccessToken={process.env.REACT_APP_MAPBOX_TOKEN}
    mapStyle={mbStyle}
    onViewportChange={(viewport) => {
      setViewport(viewport);
    }}>

      {props.rsuData.map((rsu) => (
        <Marker 
          key={rsu.id} 
          latitude={rsu.geometry.coordinates[1]} 
          longitude={rsu.geometry.coordinates[0]}>

          <button 
            className="marker-btn" 
            onClick={(e) => {
            e.preventDefault();
            setSelectedRsu(rsu);
            if (props.rsuCounts.hasOwnProperty(rsu.properties.Ipv4Address))
              setSelectedRsuCount(props.rsuCounts[rsu.properties.Ipv4Address].count);
            else
              setSelectedRsuCount(0);
          }}>
            <RsuMarker onlineStatus={rsu.onlineStatus}/>
          </button>

        </Marker>
      ))}

      {selectedRsu ? (
        <Popup
          latitude={selectedRsu.geometry.coordinates[1]} 
          longitude={selectedRsu.geometry.coordinates[0]}
          onClose={() => {
            setSelectedRsu(null);
            setSelectedRsuCount(null);
          }}>

          <div>
            <h2 className="popop-h2">{selectedRsu.properties.Ipv4Address}</h2>
            <p className="popop-p">Online Status: {selectedRsu.onlineStatus}</p>
            <p className="popop-p">Milepost: {selectedRsu.properties.Milepost}</p>
            <p className="popop-p">
              Serial Number: {selectedRsu.properties.SerialNumber ? 
              selectedRsu.properties.SerialNumber : 'Unknown'}
            </p>
            <p className="popop-p">BSM Counts: {selectedRsuCount}</p>
          </div>

        </Popup>
      ) : null}
      
  </ReactMapGL>
</div>
);
}

 export default Map;

现有改写版本的报错

src\components\Map.js
Line 24:36:  'viewport' is not defined             no-undef
Line 25:5:   'render' is not defined               no-undef
Line 30:21:  'viewport' is not defined             no-undef
Line 34:19:  'setViewport' is not defined          no-undef
Line 47:25:  'setSelectedRsu' is not defined       no-undef
Line 49:27:  'setSelectedRsuCount' is not defined  no-undef
Line 51:27:  'setSelectedRsuCount' is not defined  no-undef
Line 59:20:  'selectedRsu' is not defined          no-undef
Line 61:33:  'selectedRsu' is not defined          no-undef
Line 62:34:  'selectedRsu' is not defined          no-undef
Line 64:25:  'setSelectedRsu' is not defined       no-undef
Line 65:25:  'setSelectedRsuCount' is not defined  no-undef
Line 69:47:  'selectedRsu' is not defined          no-undef
Line 70:60:  'selectedRsu' is not defined          no-undef
Line 71:55:  'selectedRsu' is not defined          no-undef
Line 73:43:  'selectedRsu' is not defined          no-undef
Line 76:57:  'selectedRsuCount' is not defined     no-undef

需要修正的核心点

  • 语法结构错误:constructor未闭合导致render方法被定义在constructor内部,删除constructor里多余的this.setState({'viewport': viewport});语句,同时删除无用的import {render} from 'react-dom';引入。
  • state命名问题:初始state里的SelectedRsu、SelectedRsuCount首字母大写,和使用时的小写不一致,统一修改为小写开头。
  • 变量引用规则:类组件中所有state变量需要加this.state.前缀,所有props变量需要加this.props.前缀,比如viewport改为this.state.viewport,props.rsuData改为this.props.rsuData。
  • 状态更新规则:类组件没有useState返回的自定义更新函数,所有状态更新统一使用this.setState()方法,比如更新viewport改为this.setState({viewport}),更新selectedRsu改为this.setState({selectedRsu: rsu})。
  • 生命周期适配:原来useEffect实现的键盘监听,替换为componentDidMount生命周期添加监听,componentWillUnmount生命周期移除监听。
  • 属性名修正:React中class属性要改为className,所有class="xxx"修改为className="xxx"。

修正后完整代码

import React, { Component } from 'react';
import ReactMapGL, { Marker, Popup } from "react-map-gl"
import RsuMarker from './RsuMarker';
import mbStyle from '../styles/mb_style.json';

class Map extends Component {
  constructor(props) {
    super(props)
    this.state = {
      viewport: {
        latitude: 39.7392,
        longitude: -104.9903,
        width: 'calc(100% - 350px)',
        height: '100vh',
        zoom: 10
      },
      selectedRsu: null,
      selectedRsuCount: null,
    }
  }

  componentDidMount() {
    // 替换原来的useEffect添加监听
    this.escListener = e => {
      if (e.key === "Escape")
        this.setState({selectedRsu: null});
    };
    window.addEventListener("keydown", this.escListener);
  }

  componentWillUnmount() {
    // 组件卸载时移除监听
    window.removeEventListener("keydown", this.escListener);
  }

  render() {
    const { viewport, selectedRsu, selectedRsuCount } = this.state;
    return (
      <div>
        <ReactMapGL 
          {...viewport} 
          mapboxApiAccessToken={process.env.REACT_APP_MAPBOX_TOKEN}
          mapStyle={mbStyle}
          onViewportChange={(viewport) => {
            this.setState({viewport});
          }}>

            {this.props.rsuData.map((rsu) => (
              <Marker 
                key={rsu.id} 
                latitude={rsu.geometry.coordinates[1]} 
                longitude={rsu.geometry.coordinates[0]}>

                <button 
                  className="marker-btn" 
                  onClick={(e) => {
                  e.preventDefault();
                  if (this.props.rsuCounts.hasOwnProperty(rsu.properties.Ipv4Address)) {
                    this.setState({
                      selectedRsu: rsu,
                      selectedRsuCount: this.props.rsuCounts[rsu.properties.Ipv4Address].count
                    })
                  } else {
                    this.setState({
                      selectedRsu: rsu,
                      selectedRsuCount: 0
                    })
                  }
                }}>
                  <RsuMarker onlineStatus={rsu.onlineStatus}/>
                </button>

              </Marker>
            ))}

            {selectedRsu ? (
              <Popup
                latitude={selectedRsu.geometry.coordinates[1]} 
                longitude={selectedRsu.geometry.coordinates[0]}
                onClose={() => {
                  this.setState({
                    selectedRsu: null,
                    selectedRsuCount: null
                  })
                }}>

                <div>
                  <h2 className="popop-h2">{selectedRsu.properties.Ipv4Address}</h2>
                  <p className="popop-p">Online Status: {selectedRsu.onlineStatus}</p>
                  <p className="popop-p">Milepost: {selectedRsu.properties.Milepost}</p>
                  <p className="popop-p">
                    Serial Number: {selectedRsu.properties.SerialNumber ? 
                    selectedRsu.properties.SerialNumber : 'Unknown'}
                  </p>
                  <p className="popop-p">BSM Counts: {selectedRsuCount}</p>
                </div>

              </Popup>
            ) : null}
            
        </ReactMapGL>
      </div>
    );
  }
}

export default Map;

内容的提问来源于stack exchange,提问作者Poala

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 12:06:00