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

时间:2020-10-07 00:12:54

标签: javascript reactjs react-native

我目前收到“最大更新深度”错误,不确定为什么。在我的代码中看不到无限循环。

“超过了最大更新深度。当组件在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 + 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
};

似乎是以下代码上的错误:超出最大更新深度。当组件在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: ${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
    };

1 个答案:

答案 0 :(得分:0)

如果Location.isDeviceLocation不断更新并因此每次触发useEffect,就会发生这种情况。您能否显示其余的LocationSheet组件?

编辑:尝试将fetchRegions添加到依赖项数组中。

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