ReactNative:超过最大更新深度错误
Posted
技术标签:
【中文标题】ReactNative:超过最大更新深度错误【英文标题】:ReactNative: Maximum update depth exceeded error 【发布时间】:2021-01-21 21:38:21 【问题描述】:我目前遇到最大更新深度错误,不知道为什么。在我的代码中看不到无限循环。
“超过最大更新深度。当组件在 useEffect 中调用 setState,但 useEffect 没有依赖数组,或者每次渲染时其中一个依赖项发生变化时,就会发生这种情况。”
Error Shown here
ReactJS 组件代码:
import useNavigation from '@react-navigation/native';
import StackNavigationProp from '@react-navigation/stack';
import BottomSheet from 'react-native-raw-bottom-sheet';
import React, useRef from 'react';
import styled from 'styled-components/native';
import AnimatedSpinner, Button, ButtonIcon, DropShadow, Block, Row from '../../../components';
import BottomTabsType from '../../../navigation/BottomTabs';
import Colors from '../../Theme';
import useLocation from '../../../context/location';
import LocationSheet from '../LocationSheet';
import Icons from '../../../assets/icons';
type ScreenNavigationProp = StackNavigationProp<BottomTabsType, 'Home'>;
/**
* Component definition
*/
const LocationButton = styled(Button)`
backgroundColor:transparent;
paddingLeft:$Block + 15px;
paddingTop:18px;
color: $Colors.GreyDark;
fontFamily: Poppins-Regular;
fontSize:12px;
`
const SearchButton = styled(ButtonIcon)`
width:40px;
height:40px;
alignItems:center;
justifyContent:center;
paddingRight:20px;
`
const Container = styled(Row)`
paddingLeft:12px;
`
/**
*
*/
const LocationHeader = () =>
const Navigation = useNavigation<ScreenNavigationProp>()
const Location = useLocation()
const locationSheetRef = useRef<BottomSheet>()
const onSearch = () =>
Navigation.navigate('Search')
const onLocation = () =>
locationSheetRef.current?.open()
return <DropShadow intensity=0.1>
<Container>
<LocationButton text=Location.label left=Location.loading ? AnimatedSpinner : Icons.IconFilter onPress=onLocation />
<LocationSheet ref=locationSheetRef />
</Container>
</DropShadow>
/**
* Module exports
*/
export
LocationHeader
;
似乎是以下代码的错误:超出了最大更新深度。当组件在 useEffect 中调用 setState 时,可能会发生这种情况,但 useEffect 要么没有依赖数组,要么每次渲染时依赖项之一发生变化。 在 ForwardRef 中(在 LocationHeader.tsx:62)
import React, MutableRefObject, useRef, useEffect, useState from 'react';
import BottomSheet from 'react-native-raw-bottom-sheet';
import styled, css from 'styled-components/native';
import Icons from '../../assets/icons'
import
TextBold, Text, ButtonWhite, Block, AsyncContent, ButtonClear, CenterFill, Row
from '../../components';
import Colors from '../Theme';
import SearchField from '../search/SearchHeader'
import useLocation from '../../context/location';
import Place from '../../models/Place';
import useApi, useUi from '../../context';
import useAsync from '../../hooks/useAsync';
import FlatList from 'react-native';
import delay, isTruthy from '../../utils/helpers';
const SearchContainer = styled(Row)`
`
const ButtonLocation = styled(ButtonWhite)`
color:$Colors.Orange;
text-align:left;
`
const PoppinsBold14 = css`
fontSize:14px;
`
const Heading = styled(TextBold)`
padding:20px;
color:$Colors.AlmostBlack;
textAlign:center;
$PoppinsBold14;
`
const SearchBlock = styled.View`
flex:1;
padding: $Blockpx;
padding-top: 0px;
`
const ErrorText = styled(Text)`
margin-top:$Block * 2px;
color:$Colors.Grey;
text-align:center;
`
const RegionsEmpty = () =>
// return <TextBold text='No matches found' />
return <CenterFill>
<Icons.ImageNoResultsLocation />
<ErrorText text=
`Location not found
Try a new search`
/>
</CenterFill>
const PlaceSeparator = styled.View`
width:100%;
height:1px;
background-color:$Colors.GreyLight;
`
const PlaceButton = styled(ButtonClear)`
text-align:left;
font-family: Poppins-Regular;
color: $Colors.AlmostBlack;
`
const PlaceItem = (props: place: Place, onClick: () => void ) =>
return <PlaceButton text=props.place.name onPress=props.onClick left=Icons.IconSearchLocation />
const LocationSheet = React.forwardRef((props, ref: React.MutableRefObject<BottomSheet>) =>
const Location = useLocation()
const Api = useApi()
const Ui = useUi()
const [query, setQuery] = useState('')
const sheetRef: MutableRefObject<BottomSheet> = ref ?? useRef<BottomSheet>()
const value: suburbs, error, loading, execute: fetchRegions = useAsync(async () =>
// const regions = await Api.getRegions()
const suburbs = await Api.getSuburbs('newyork')
return suburbs
, false);
useEffect(() =>
if (!Location.isDeviceLocation)
fetchRegions()
, [Location.isDeviceLocation])
/**
*
*/
const closeSheet = () =>
sheetRef.current?.close()
// Always reset search state on close so that list is reset on next open
setQuery('')
/**
* Handles user interaction with location toggle
*/
const onClickLocationMode = async () =>
try
if (await Location.toggleMode() === 'DeviceLocation')
// For user experience
await delay(300)
closeSheet()
catch (error)
Ui.showErrorToast(error)
/**
*
* @param place
*/
const onClickPlace = (place: Place) => async () =>
Location.setPlace(place)
// For user experience
await delay(300)
closeSheet()
/**
*
* @param place
*/
const isRegionKeywordMatch = (place: Place) =>
return place.name.match(new RegExp(query, 'gi')) !== null
return <BottomSheet
height=600
customStyles=
container:
borderTopLeftRadius: 10,
borderTopRightRadius: 10
openDuration=500
ref=sheetRef>
<Heading text="Location settings" />
<SearchBlock>
<ButtonLocation text="Use current location" onPress=onClickLocationMode left=Icons.IconSearchLocation right=Location.isDeviceLocation ? Icons.Tick : null />
<SearchContainer>
/* TODO: Search container needed to keep field icon vertically centered */
<SearchField placeholder="Search for location" onChangeText=setQuery left=Icons.IconSearch />
</SearchContainer>
<AsyncContent loading=loading error=error value=suburbs retry=fetchRegions render=suburbs =>
const suburbsFiltered = isTruthy(query) ?
suburbs.filter(isRegionKeywordMatch) :
suburbs
const hasQuery = isTruthy(query)
if (!hasQuery)
return null
else
return <FlatList
data=suburbsFiltered
ListEmptyComponent=RegionsEmpty
ItemSeparatorComponent=PlaceSeparator
keyExtractor=(region) => `$region.id`
renderItem=( item: suburb ) => <PlaceItem place=suburb onClick=onClickPlace(suburb) />
/>
/>
</SearchBlock>
</BottomSheet>
)
export
LocationSheet
;
【问题讨论】:
【参考方案1】:如果 Location.isDeviceLocation 不断更新并因此每次都会触发 useEffect,就会发生这种情况。能否请您展示 LocationSheet 组件的其余部分?
编辑:尝试将 fetchRegions 添加到依赖数组。
useEffect(() =>
if (!Location.isDeviceLocation)
fetchRegions()
, [Location.isDeviceLocation, fetchRegions])
【讨论】:
是的一秒钟! 它在 android 中似乎工作正常,只是在 ios 中似乎出现了这些错误 我唯一要更改的是将 fetchRegions 添加到依赖项数组中以确保。因为我分析了您的代码,但找不到任何可能触发 useEffect 循环的内容。 抱歉没明白:/? 我更新了答案以表明我的意思。我没有看到任何其他可能导致此问题的内容。以上是关于ReactNative:超过最大更新深度错误的主要内容,如果未能解决你的问题,请参考以下文章