![](/img/trans.png)
[英]Cannot read property 'history' of undefined (useHistory hook of React Router 5)
[英]React useRef hook causing “Cannot read property '0' of undefined” error
我正在嘗試通過執行以下操作為`data數組中的每個項目使用useRef
鈎子創建一個引用:
const markerRef = useRef(data.posts.map(React.createRef))
現在, data
是通過 GraphQL 從外部獲取的,需要時間才能到達,因此,在掛載階段, data
是undefined
。 這會導致以下錯誤:
TypeError:無法讀取未定義的屬性“0”
我嘗試了以下但沒有成功:
const markerRef = useRef(data && data.posts.map(React.createRef))
如何設置以便我可以通過data
map 而不會導致錯誤?
useEffect(() => {
handleSubmit(navigation.getParam('searchTerm', 'default value'))
}, [])
const [loadItems, { called, loading, error, data }] = useLazyQuery(GET_ITEMS)
const markerRef = useRef(data && data.posts.map(React.createRef))
const onRegionChangeComplete = newRegion => {
setRegion(newRegion)
}
const handleSubmit = () => {
loadItems({
variables: {
query: search
}
})
}
const handleShowCallout = index => {
//handle logic
}
if (called && loading) {
return (
<View style={[styles.container, styles.horizontal]}>
<ActivityIndicator size="large" color="#0000ff" />
</View>
)
}
if (error) return <Text>Error...</Text>
return (
<View style={styles.container}>
<MapView
style={{ flex: 1 }}
region={region}
onRegionChangeComplete={onRegionChangeComplete}
>
{data && data.posts.map((marker, index) => (
<Marker
ref={markerRef.current[index]}
key={marker.id}
coordinate={{latitude: marker.latitude, longitude: marker.longitude }}
// title={marker.title}
// description={JSON.stringify(marker.price)}
>
<Callout onPress={() => handleShowCallout(index)}>
<Text>{marker.title}</Text>
<Text>{JSON.stringify(marker.price)}</Text>
</Callout>
</Marker>
))}
</MapView>
</View>
)
我正在使用useLazyQuery
因為我需要在不同的時間觸發它。
更新:
根據@azundo 的建議,我已將useRef
修改為以下內容:
const dataRef = useRef(data);
const markerRef = useRef([]);
if (data && data !== dataRef.current) {
markerRef.current = data.posts.map(React.createRef);
dataRef.current = data
}
當我 console.log markerRef.current
時,我得到以下結果:
這很好。 但是,當我嘗試對每個current
進行 map 並調用showCallout()
通過執行以下操作打開每個標記的所有標注時:
markerRef.current.map(ref => ref.current && ref.current.showCallout())
什么都沒有被執行。
console.log(markerRef.current.map(ref => ref.current && ref.current.showCallout()))
這顯示了每個陣列的 null。
useRef
表達式僅在每個組件掛載時執行一次,因此您需要在data
更改時更新引用。 起初我建議useEffect
但它運行得太晚了,所以在第一次渲染時不會創建參考。 使用第二個 ref 檢查data
是否更改以同步重新生成標記 refs 應該可以代替。
const dataRef = useRef(data);
const markerRef = useRef([]);
if (data && data !== dataRef.current) {
markerRef.current = data.posts.map(React.createRef);
dataRef.current = data;
}
附加編輯:
為了在掛載的所有組件上觸發showCallout
,必須首先填充 refs。 這可能是useLayoutEffect
的適當時間,以便它在標記呈現並設置參考值(應該?)后立即運行。
useLayoutEffect(() => {
if (data) {
markerRef.current.map(ref => ref.current && ref.current.showCallout());
}
}, [data]);
使用 memoisation 創建 refs,例如:
const markerRefs = useMemo(() => data && data.posts.map(d => React.createRef()), [data]);
然后像這樣渲染它們:
{data &&
data.posts.map((d, i) => (
<Marker key={d} data={d} ref={markerRefs[i]}>
<div>Callout</div>
</Marker>
))}
並使用 refs 調用命令式函數,例如:
const showAllCallouts = () => {
markerRefs.map(r => r.current.showCallout());
};
使用模擬Marker
查看工作代碼: https://codesandbox.io/s/muddy-bush-gfd82
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.