React native - Maximum call stack size exceeded

javascript, react-native, reactjs

Solution

It's because you are rendering another `<SearchPage />` within your menu: `renderScene: <SearchPage />`. This creates a circular dependency where a SearchPage is creating a Menu and the Menu is creating a SearchPage... etc. Until, as you saw, you run out of memory.

Problem

When I add the `<Menu />` component to my header as below: ``` let SearchPage = (props) => { const menu = ( <Container> <Header style={styles.header}> <Left> <Button > <Menu /> </Button> </Left> <Body> ``` I get the error Maximum call stack size exceeded and of course if I comment out the `<Menu />` line in my `SearchPage`, there is no error. The menu is a react-native-off-canvas-menu My menu component: components/menu/Menu.js ``` import React from 'react' import { View, Icon } from 'react-native' import { connect } from 'react-redux' import { togglePageMenu } from './menu.action' import { OffCanvas3D } from 'react-native-off-canvas-menu' //import AddPage from '../add-page/AddPage' import SearchPage from '../search-page/SearchPage' const mapStateToProps = (state) => ({ isOpen: state.get('menu').isOpen }) const mapDispatchToProps = (dispatch) => ({ togglePageMenu: () => { dispatch(togglePageMenu()) } }) let Menu = (props) => ( <View style={{ flex: 1 }}> <OffCanvas3D active={props.isOpen} onMenuPress={props.togglePageMenu} backgroundColor={'#222222'} menuTextStyles={{ color: 'white' }} handleBackPress={true} menuItems={[ { title: 'Search Products', icon: <Icon name="camera" size={35} color='#ffffff' />, renderScene: <SearchPage /> } ]} /> </View> ) Menu.propTypes = { togglePageMenu: React.PropTypes.func.isRequired, isOpen: React.PropTypes.bool.isRequired } Menu = connect( mapStateToProps, mapDispatchToProps )(Menu) export default Menu ``` What could be causing the error? Here is my component that uses the menu (probably not relevant): components/search-page/SearchPage.js ``` import { ScrollView, StyleSheet, View } from 'react-native' import { Container, Button, Text, Header, Body, Right, Left, Title, Icon } from 'native-base' import React from 'react' import Keywords from '../keywords/Keywords' import Categories from '../categories/Categories' import Location from '../location/Location' import Menu from '../menu/Menu' import DistanceSlider from '../distanceSlider/DistanceSlider' import Map from '../map/Map' import Drawer from 'react-native-drawer' import { connect } from 'react-redux' import { toggleMenu } from './searchPage.action' import { styles, wideButtonColor } from '../../style' import searchPageStyle from './style' import { selectIsSearchFormValid } from './isSearchFormValid.selector' const mapStateToProps = (state) => ({ isMenuOpen: state.get('searchPage').get('isMenuOpen'), isSearchFormValid: selectIsSearchFormValid(state) }) const mapDispatchToProps = (dispatch) => ({ toggleMenu: () => { dispatch(toggleMenu()) } }) let SearchPage = (props) => { const menu = ( <Container> <Header style={styles.header}> <Left> <Button > <Menu /> </Button> </Left> <Body> <Title style={styles.title}>Search Products</Title> </Body> <Right> </Right> </Header> <Container style={styles.container}> <ScrollView keyboardShouldPersistTaps={true}> <Categories /> <View style={searchPageStyle.locationContainer}> <Location /> </View> <DistanceSlider /> <Keywords /> <Button block style={{ ...searchPageStyle.goButton, backgroundColor: wideButtonColor(!props.isSearchFormValid) }} disabled={!props.isSearchFormValid} onPress={props.toggleMenu}> <Text>GO</Text> </Button> </ScrollView> </Container> </Container> ) return ( <Drawer open={props.isMenuOpen} content={menu}> <Container style={mapStyles.container}> <Map /> </Container> </Drawer> ) } SearchPage.propTypes = { toggleMenu: React.PropTypes.func.isRequired, isMenuOpen: React.PropTypes.bool.isRequired, isSearchFormValid: React.PropTypes.bool.isRequired } SearchPage = connect( mapStateToProps, mapDispatchToProps )(SearchPage) export default SearchPage const mapStyles = StyleSheet.create({ container: { ...StyleSheet.absoluteFillObject, height: 400, width: 400, justifyContent: 'flex-end', alignItems: 'center', } }) ```

Original source