useRef 值在初始渲染时未定义

问题描述 投票:0回答:4

我正在用react和react-leaflet制作一张地图。 React Leaflet 有一个名为 FeatureGroup 的类,我想在第一次渲染时使用 React 中的 useRef 钩子访问该类,然后访问 useEffect 函数中的值。然而,在初始渲染时,ref 未定义(markerRef.current 返回 null)。只有在我对代码进行任何类型的更改、保存并重新加载 React 应用程序后,它才会获得值

你能告诉我我做错了什么,以及如何使markerRef.current在初始渲染上不为空吗?

请在下面找到该组件的缩写代码:

import {useRef} from 'react';
import {FeatureGroup, //... } from 'react-leaflet';

const MapView = ({breweries}) => {
  const markerGroupRef = useRef(null);
  //...
  useEffect(() => {
    if(markerGroupRef.current) {
      //here I want to access a method called getBounds() which is in the markerGroupRef.current object 
      //but markerGroupRef.current has null value and so it doesn't execute
      //when making a save change and react app reloads it has the FeatureGroup class as value as expected
      console.log(markerGroupRef.current)
    }
  }, [markerGroupRef])
  //...
  return (
            <FeatureGroup ref={markerGroupRef}>
              {breweries && breweries.map(brewery => <Brewery key={breweries.indexOf(brewery)} brewery={brewery}/>)}
              {breweryStore && breweryStore.searchLocation &&  <LocationMarker markerPosition={{lat: breweryStore.searchLocation.lat, lng: breweryStore.searchLocation.lon}}/>}
            </FeatureGroup>
    );
  }

reactjs react-leaflet
4个回答
10
投票

useRef 创建的引用不会触发组件重新渲染。因此您创建的 useRef 挂钩将永远不会执行。此外,由于您将 ref 初始化为 null,因此在第一次渲染开始时,它将保持为 null。在第一次渲染期间,

ref={markerGroupRef}
上的
FeatureGroup
将更新它,但同样不会触发另一次渲染。必须修改状态才能触发任何可能的重新渲染

您可能想要使用回调引用,如此处

所示
function MeasureExample() {
  const [height, setHeight] = useState(0);

  const measuredRef = useCallback(node => {
    if (node !== null) {
      setHeight(node.getBoundingClientRect().height);
    }
  }, []);

  return (
    <>
      <h1 ref={measuredRef}>Hello, world</h1>
      <h2>The above header is {Math.round(height)}px tall</h2>
    </>
  );
}

并在这里证明合理这里

请记住,useRef 的内容更改时不会通知您。 改变 .current 属性不会导致重新渲染。如果你想 当 React 将 ref 附加或分离到 DOM 节点时运行一些代码, 您可能想改用回调引用。


4
投票

您的问题是更新引用不会使组件重新渲染,因此 useEffect 只运行一次,并且在第一次渲染时引用仍然为空。

您所描述的是正确的行为,您需要等待重新渲染才能对引用执行任何操作。如果强制重新渲染,您将能够使用 ref.current 属性:

    const MapView = ({ breweries }) => {
        const markerGroupRef = useRef(null);
        const [refAquired, setRefAquired] = useState(false)
        //...
        useEffect(() => {
            setRefAquired(true)
        }, []);

        useEffect(()=> {
            console.log(markerGroupRef.current)
        }, [refAquired])

这是一个粗略的演示,您应该尝试使渲染周期与其他渲染和业务逻辑相结合。


0
投票

作为替代方案,您可以通过

useEffect
钩子强制组件在初始渲染后立即再次渲染,从而确保对元素的访问。我不确定这是否是最佳实践,但老实说,对性能的影响很小。

const [shouldUpdate, setShouldUpdate] = useState(true)

// set shouldUpdate => true on initial render, triggering re-render
useEffect(() => {
  if (shouldUpdate) setShouldUpdate(false)
}, [shouldUpdate])

0
投票

我也有同样的问题;当尝试在

<Map ref={mapRef
期间使用它时,未定义
useEffect []
引用。

上面的建议都不适合我......但他们确实告诉我,当设置引用时,它不会导致重新渲染。

所做的工作是找到

<Map onLoad={()=>setMapLoaded(true)
onLoad
道具。

有了这个道具,我就能够触发我必要的

useEffect
并且它按预期工作。

© www.soinside.com 2019 - 2024. All rights reserved.