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:超过最大更新深度错误的主要内容,如果未能解决你的问题,请参考以下文章

我从 React 得到一个错误:超过最大更新深度

反应“错误:超过最大更新深度。”带有功能组件和钩子

React App登录错误:超过最大更新深度

超过最大更新深度 - React Js

useEffect & map 超过了最大更新深度

加载页面时如何始终调用 onClick?错误:超过最大更新深度 [重复]