【问题标题】:Avoid component re-rendering when passing props to child component将 props 传递给子组件时避免组件重新渲染
【发布时间】:2021-04-15 04:13:22
【问题描述】:

我对 React 比较陌生,目前我被困住了。基本上,我从 API 获取数据并递归地使用标记填充 MAPBOX。我有一个App 组件,我从中获取数据,一个Map 组件,我在其中设置地图及其所有属性,然后我有InfoHeader 组件来显示我从API 获取的更多数据。

我将要存储在状态中的数据传递给InfoHeader 的方式是,一旦单击地图中的标记之一,就通过道具。

当前问题: 单击标记后,我将重新渲染整个 Map 组件,因此弹出窗口永远不会显示,即使数据正确传递给 InfoHeader,我也不希望 Map 重新渲染,只有 InfoHeader

我尝试过使用 React.memo,但到目前为止还没有成功。

代码

Map.js

import React, {useEffect, useRef, useState} from 'react'
import mapboxgl from 'mapbox-gl'
import InfoHeader from './InfoHeader'

mapboxgl.accessToken = "pk.eyJ1IjoibGVob3VkaW5pIiwiYSI6ImNram43b3FhZTNzYWUydnNjd21zcmJ1d2QifQ.ouLhKn6B6pzmbZJtymQIcg"

const Map = React.memo(({data}) => {

    const mapRef = useRef(null)

    useEffect(() => {
        const map = new mapboxgl.Map({
            container: mapRef.current,

            style: 'mapbox://styles/mapbox/dark-v10',
            center: [-104.9876, 39.7405],
            zoom: 1.5,
        })

       //Marker logic in async func 
       addMarkerToMap(data, map)
        

          // add navigation control (the +/- zoom buttons)
        map.addControl(new mapboxgl.NavigationControl(), 'bottom-right');


        return () => {
            //cleanup when unmounting
            map.remove()
        }
    })
    
    //state to be passed to InfoHeader
    const [population, setPopulation] = useState()
    const [infected, setInfected] = useState()
    const [recovered, setRecovered] = useState()

    const addMarkerToMap = async (mapData, map) =>  {
        if(Object.keys(mapData).length) {
            mapData.forEach(el => {
                const {countryInfo, country, cases, population, recovered, deaths} = el
                const {lat, long, flag} = countryInfo
                console.log(el)
                const marker = new mapboxgl.Marker()
                .setLngLat([long, lat])
                .setPopup(new mapboxgl.Popup().setHTML(
                    `<img style="width: 100%" src=${flag} alt="flag"/> <h1 style="text-align:center; color: #fcfcfc">${country}</h1>
                    <p>Population: ${population}</p>
                    <p>Number of cases: ${cases}</p>
                    <p>Deaths: ${deaths}
                    <p>Recovered: ${recovered}</p>
                `))
                .addTo(map)
                marker.getElement().addEventListener('click', () => {
                    setPopulation(population)
                    setInfected(cases)
                    setRecovered(recovered)
                })
            })
        }
    }

    return(
        <div className="map-wrapper">
            <InfoHeader
                population = {population}
                infected = {infected}
                recovered = {recovered}
            />
            <div className="map-container" ref={mapRef}>

            </div>
        </div>
    )
})

export default Map

InfoHeader.js

import React from 'react'

const InfoHeader = ({population, infected, recovered}) => {

    return(
        <div className="infoHeader-wrapper">
            <div className="infoHeader-population">
                <h2 className="info-title">Population</h2>
                <p className="info-data">{population}</p>
            </div>
            <div className="infoHeader-infected">
                <h2 className="info-title">Infected</h2>
                <p className="info-data">{infected}</p>
            </div>
            <div className="infoHeader-recovered">
                <h2 className="info-title">Recovered</h2>
                <p className="info-data">{recovered}</p>
            </div>
        </div>
    )
}

export default InfoHeader

任何帮助都会令人惊叹,即使它指向一些资源来阅读更多关于我做错的事情。谢谢!

【问题讨论】:

    标签: javascript html reactjs rendering


    【解决方案1】:

    为避免您的 useEffect 钩子再次运行,请添加一个空数组作为第二个参数。

    来自useEffect上的 React.js 文档

    如果你想运行一个效果并且只清理一次(在挂载和卸载时),你可以传递一个空数组([])作为第二个参数。这告诉 React 你的效果不依赖于任何来自 props 或 state 的值,所以它永远不需要重新运行。这不是作为特殊情况处理的——它直接遵循依赖项数组的工作方式。

    useEffect(() => {
      const map = new mapboxgl.Map({
        container: mapRef.current,
        style: 'mapbox://styles/mapbox/dark-v10',
        center: [-104.9876, 39.7405],
        zoom: 1.5,
      })
    
      //Marker logic in async func 
      addMarkerToMap(data, map)
    
      // add navigation control (the +/- zoom buttons)
      map.addControl(new mapboxgl.NavigationControl(), 'bottom-right');
    
      return () => {
        //cleanup when unmounting
        map.remove()
      }
    }, [])
    

    【讨论】:

    • 作为快速编辑,我必须将数据放入依赖数组中才能呈现标记
    猜你喜欢
    • 2018-06-04
    • 2018-12-24
    • 2020-12-26
    • 2019-12-05
    • 2022-06-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多