简体   繁体   English

ReactNative:超出最大更新深度错误

[英]ReactNative: Maximum update depth exceeded error

I'm currently getting a Maxiumum Update depth error not sure why.我目前收到最大更新深度错误,不知道为什么。 Don't quite see the infinite loop in my code.不太清楚我的代码中的无限循环。

"Maximum update depth exceeded. This can happen when a component calls setState inside useEffect, but useEffect either doesn't have a dependency array, or one of the dependencies changes on every render." “超出了最大更新深度。当组件在 useEffect 中调用 setState 时,可能会发生这种情况,但 useEffect 要么没有依赖项数组,要么依赖项之一在每次渲染时发生变化。”

Error Shown here此处显示错误

ReactJS Component Code: 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 + 15}px;
  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
};

Seems to be an error on the code below: Maximum update depth exceeded.下面的代码似乎是一个错误:超出最大更新深度。 This can happen when a component calls setState inside useEffect, but useEffect either doesn't have a dependency array, or one of the dependencies changes on every render.当组件在 useEffect 中调用 setState 时会发生这种情况,但 useEffect 要么没有依赖项数组,要么依赖项之一在每次渲染时发生变化。 in ForwardRef (at LocationHeader.tsx:62)在 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: ${Block}px;
      padding-top: 0px;
    `
    
    const ErrorText = styled(Text)`
    margin-top:${Block * 2}px;
    color:${Colors.Grey};
      text-align:center;
    `
    
    const RegionsEmpty = () => {
    
      // return <TextBold text='No matches found' />
      return <CenterFill>
        <Icons.ImageNoResultsLocation width="150px" height="150px" />
        <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
    };

This would happen if the Location.isDeviceLocation is being updated constantly and therefore triggering the useEffect everytime.如果 Location.isDeviceLocation 不断更新并因此每次触发 useEffect,就会发生这种情况。 Could you please show the rest of the LocationSheet component?您能否展示 LocationSheet 组件的其余部分?

Edit: Try adding fetchRegions to the dependency array.编辑:尝试将 fetchRegions 添加到依赖项数组。

 useEffect(() => {
    
        if (!Location.isDeviceLocation) {
          fetchRegions()
        }
    
      }, [Location.isDeviceLocation, fetchRegions])

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM