我正在用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>
);
}
由 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 节点时运行一些代码, 您可能想改用回调引用。
您的问题是更新引用不会使组件重新渲染,因此 useEffect 只运行一次,并且在第一次渲染时引用仍然为空。
您所描述的是正确的行为,您需要等待重新渲染才能对引用执行任何操作。如果强制重新渲染,您将能够使用 ref.current 属性:
const MapView = ({ breweries }) => {
const markerGroupRef = useRef(null);
const [refAquired, setRefAquired] = useState(false)
//...
useEffect(() => {
setRefAquired(true)
}, []);
useEffect(()=> {
console.log(markerGroupRef.current)
}, [refAquired])
这是一个粗略的演示,您应该尝试使渲染周期与其他渲染和业务逻辑相结合。
作为替代方案,您可以通过
useEffect
钩子强制组件在初始渲染后立即再次渲染,从而确保对元素的访问。我不确定这是否是最佳实践,但老实说,对性能的影响很小。
const [shouldUpdate, setShouldUpdate] = useState(true)
// set shouldUpdate => true on initial render, triggering re-render
useEffect(() => {
if (shouldUpdate) setShouldUpdate(false)
}, [shouldUpdate])
我也有同样的问题;当尝试在
<Map ref={mapRef
期间使用它时,未定义 useEffect []
引用。
上面的建议都不适合我......但他们确实告诉我,当设置引用时,它不会导致重新渲染。
所做的工作是找到
<Map onLoad={()=>setMapLoaded(true)
onLoad
道具。
有了这个道具,我就能够触发我必要的
useEffect
并且它按预期工作。