如何在 React 中将函数转换为基于 class 的组件?

How to convert function to class based components in react?

我正在尝试将基于函数的组件转换为基于 class 的组件。有人可以指导我如何做到这一点: 这是基于函数的组件:

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

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

 export default Map;

这是我到目前为止所做的。它并不多,但是任何关于正确方向的指导,例如我需要在代码中修复的事情,都将不胜感激。在这一点上有点失落。

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

     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,
        }

        this.setState({'viewport': viewport});
    render()
    {
        return (
            <div>
              <ReactMapGL 
                {...viewport} 
                mapboxApiAccessToken={process.env.REACT_APP_MAPBOX_TOKEN}
                mapStyle={mbStyle}
                onViewportChange={(viewport) => {
                  setViewport(this.viewport);
                }}>
        
                  {props.rsuData.map((rsu) => (
                    <Marker 
                      key={rsu.id} 
                      latitude={rsu.geometry.coordinates[1]} 
                      longitude={rsu.geometry.coordinates[0]}>
        
                      <button 
                        class="marker-btn" 
                        onClick={(e) => {
                        e.preventDefault();
                        setSelectedRsu(rsu);
                        if (props.rsuCounts.hasOwnProperty(rsu.properties.Ipv4Address))
                          setSelectedRsuCount(this.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 class="popop-h2">{selectedRsu.properties.Ipv4Address}</h2>
                        <p class="popop-p">Online Status: {selectedRsu.onlineStatus}</p>
                        <p class="popop-p">Milepost: {selectedRsu.properties.Milepost}</p>
                        <p class="popop-p">
                          Serial Number: {selectedRsu.properties.SerialNumber ? 
                          this.props.selectedRsu.properties.SerialNumber : 'Unknown'}
                        </p>
                        <p class="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

class 组件看起来像这样。

import React, { Component } from "react";
import ReactMapGL, { Marker, Popup } from "react-map-gl";

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
    };
  }

  render() {
    const { viewport, selectedRsu, selectedRsuCount } = this.state;
    return (
      <div>
        <ReactMapGL
          {...viewport}
          mapboxApiAccessToken={process.env.REACT_APP_MAPBOX_TOKEN}
          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
                class="marker-btn"
                onClick={(e) => {
                  e.preventDefault();
                  this.setState({
                    selectedRsu: rsu
                  });
                }}
              ></button>
            </Marker>
          ))}

          {selectedRsu ? (
            <Popup
              latitude={selectedRsu.geometry.coordinates[1]}
              longitude={selectedRsu.geometry.coordinates[0]}
              onClose={() => {
                this.setState({
                  selectedRsu: null,
                  selectedRsuCount: null
                });
              }}
            >
              <div>
                <h2 class="popop-h2">{selectedRsu.properties.Ipv4Address}</h2>
                <p class="popop-p">Online Status: {selectedRsu.onlineStatus}</p>
                <p class="popop-p">
                  Milepost: {selectedRsu.properties.Milepost}
                </p>
                <p class="popop-p">
                  Serial Number:{" "}
                  {selectedRsu.properties.SerialNumber
                    ? selectedRsu.properties.SerialNumber
                    : "Unknown"}
                </p>
                <p class="popop-p">BSM Counts: {selectedRsuCount}</p>
              </div>
            </Popup>
          ) : null}
        </ReactMapGL>
      </div>
    );
  }
}

export default Map;

使用 React Class 组件时的注意事项。

  • 访问道具时,通过this.props.propName访问。
  • 访问状态变量时,通过this.state.stateVariableName访问。
  • 设置状态时,使用具有新值的对象进行设置,例如:this.setState({stateVariableName: 'newValue' }),该对象将与现有的 state.
  • 合并

你为什么又要设置状态 您已经在构造函数中设置了状态。

删除有效的设置状态行。 查看文章以了解有关基于 class 的组件的更多信息。 https://medium.com/swlh/class-based-components-in-react-440eb8ed85a0

别忘了您还需要转换这部分代码:

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

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

看起来您只是在组件安装和卸载时使用效果,这是一个简单的解决方法。只需将 onmount 代码移动到 componentWillMount 并将卸载代码移动到 componentWillUmount:

import React, { Component } from "react";
import ReactMapGL, { Marker, Popup } from "react-map-gl";

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
    };
  }
  //in order to be accessible to componentWillUnMount your listener has to be global
  listener = e => {
      if (e.key === "Escape")
      setState({selectedRsu:null});
     };
  componentDidMount(){
    window.addEventListener("keydown", this.listener);
  }
  componentWillUnmount(){
     window.removeEventListener("keydown", this.listener);
  }

  render() {
    const { viewport, selectedRsu, selectedRsuCount } = this.state;
    return (
      <div>
        <ReactMapGL
          {...viewport}
          mapboxApiAccessToken={process.env.REACT_APP_MAPBOX_TOKEN}
          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
                class="marker-btn"
                onClick={(e) => {
                  e.preventDefault();
                  this.setState({
                    selectedRsu: rsu
                  });
                }}
              ></button>
            </Marker>
          ))}

          {selectedRsu ? (
            <Popup
              latitude={selectedRsu.geometry.coordinates[1]}
              longitude={selectedRsu.geometry.coordinates[0]}
              onClose={() => {
                this.setState({
                  selectedRsu: null,
                  selectedRsuCount: null
                });
              }}
            >
              <div>
                <h2 class="popop-h2">{selectedRsu.properties.Ipv4Address}</h2>
                <p class="popop-p">Online Status: {selectedRsu.onlineStatus}</p>
                <p class="popop-p">
                  Milepost: {selectedRsu.properties.Milepost}
                </p>
                <p class="popop-p">
                  Serial Number:{" "}
                  {selectedRsu.properties.SerialNumber
                    ? selectedRsu.properties.SerialNumber
                    : "Unknown"}
                </p>
                <p class="popop-p">BSM Counts: {selectedRsuCount}</p>
              </div>
            </Popup>
          ) : null}
        </ReactMapGL>
      </div>
    );
  }
}

export default Map;