如何在反应中将函数转换为基于类的组件?

Posted

技术标签:

【中文标题】如何在反应中将函数转换为基于类的组件?【英文标题】:How to convert function to class based components in react? 【发布时间】:2021-12-09 13:20:51 【问题描述】:

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

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

【问题讨论】:

什么是viewport ?它应该是组件道具吗? 是的,基于函数的函数 Map(props) const [viewport, setViewport] = useState( latitude: 39.7392, longitude: -104.9903, width: 'calc(100% - 350px)',高度:'100vh',缩放:10 ); 啊,我明白了。它是一个状态变量,而不是一个道具。 【参考方案1】:

类组件看起来像这样。

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 合并。

【讨论】:

【参考方案2】:

别忘了你也需要转换这部分代码:

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

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

看起来您只是在组件安装和卸载时使用效果,这是一个简单的修复。只需将安装代码移至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;

【讨论】:

【参考方案3】:

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

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

【讨论】:

以上是关于如何在反应中将函数转换为基于类的组件?的主要内容,如果未能解决你的问题,请参考以下文章

如何将此基于 ReactJS 类的组件转换为基于函数的组件?

反应JS |将函数组件更改为基于类的引用错误

如何在反应中将数组从子组件发送到父组件?

如何在反应中将功能和对象传输到功能组件

如何在反应中将分钟转换为小时和分钟

如何在反应中将className添加到组件?