How to send custom props to my custom searchPanel from devExtreme - javascript

So i want to pass my custom onChange function to my custom plugin in ReactJS with devextreme grid.
I have my searchPanel override like this:
import { withComponents } from '#devexpress/dx-react-core';
import { SearchPanel as SearchPanelBase } from '#devexpress/dx-react-grid';
import { SearchPanelInput as Input } from './SearchPanelInputBase';
export const SearchPanel = withComponents({ Input })(SearchPanelBase);
and then my searchPanelInputBase
import * as React from 'react';
import * as PropTypes from 'prop-types';
import { withStyles } from '#material-ui/core/styles';
import Input from '#material-ui/core/Input';
import InputAdornment from '#material-ui/core/InputAdornment';
import Search from '#material-ui/icons/Search';
import { Switch } from '#material-ui/core';
import StoreUsers from '../store/StoreUsers';
const styles = theme => ({
root: {
display: 'flex',
alignItems: 'center',
color: theme.palette.action.active,
},
flexSpaced: {
display: 'flex',
flexDirection: 'row',
justifyContent: 'space-between',
width: '100%',
}
});
let getActives = false
const SearchPanelInputBase = ({
myCustomFunctionFromProps, classes, onValueChange, value, getMessage, props, ...restProps
}) => (
<div className={classes.flexSpaced}>
<Switch
onChange={myCustomFunctionFromProps}
/>
<Input
onChange={e => onValueChange(e.target.value)}
value={value}
type="text"
placeholder={getMessage('searchPlaceholder')}
{...restProps}
startAdornment={(
<InputAdornment position="start">
<Search />
</InputAdornment>
)}
/>
</div>
);
SearchPanelInputBase.propTypes = {
myCustomFunctionFromProps: PropTypes.func.isRequired,
onValueChange: PropTypes.func.isRequired,
value: PropTypes.string,
getMessage: PropTypes.func.isRequired,
};
SearchPanelInputBase.defaultProps = {
value: '',
};
export const SearchPanelInput = withStyles(styles)(SearchPanelInputBase);
Finally i call in where i want like this
<SearchPanel
inputComponent={props => (
<SearchPanelInput myCustomFunctionFromProps={this.myCustomFunctionFromProps} {...props} />
)}
/>
But this is not working, my prop types say the function is undefined, i suspect the props are not spreading correctly but i do not know how to override the other component
EDIT:
my function
myCustomFunctionFromProps = () => console.log('lel')

withComponents is not passing down your custom props.
It can be used with several components:
export const Table = withComponents({ Row, Cell })(TableBase);
And it just HOC for:
<TableBase
rowComponent={Row}
cellComponent={Cell}
/>
So how should it know to which one custom props go?
You have to define another Input wrapper in scope with myCustomFunctionFromProps function.
Input2 = props => (
<SearchPanelInput myCustomFunctionFromProps={this.myCustomFunctionFromProps} {...props} />
)
and use SearchPanel from #devexpress/dx-react-grid
<SearchPanel
inputComponent={this.Input2}
/>
also you should change:
onChange={() => myCustomFunctionFromProps}
myCustomFunctionFromProps={() => this.myCustomFunctionFromProps}
to:
onChange={myCustomFunctionFromProps}
myCustomFunctionFromProps={this.myCustomFunctionFromProps}
or (although it's renundant):
onChange={() => myCustomFunctionFromProps()}
myCustomFunctionFromProps={() => this.myCustomFunctionFromProps()}

Related

MUI Custom Text Field loses focus on state change

I'm using MUI library to create my React Js app.
Here I'm using the controlled Text Field component to create a simple search UI.
But there is something strange. The Text Field component loses focus after its value is changed.
This is my first time facing this problem. I never faced this problem before.
How this could happen? And what is the solution.
Here is the code and the playground: https://codesandbox.io/s/mui-autocomplete-lost-focus-oenoo?
Note: if I remove the breakpoint type from the code, the Text Field component still loses focus after its value is changed.
It's because you're defining a component inside another component, so that component definition is recreated every time the component renders (and your component renders every time the user types into the input).
Two solutions:
Don't make it a separate component.
Instead of:
const MyComponent = () => {
const MyInput = () => <div><input /></div>; // you get the idea
return (
<div>
<MyInput />
</div>
);
};
Do:
const MyComponent = () => {
return (
<div>
<div><input /></div> {/* you get the idea */}
</div>
);
};
Define the component outside its parent component:
const MyInput = ({value, onChange}) => (
<div>
<input value={value} onChange={onChange} />
</div>
);
const MyComponent = () => {
const [value, setValue] = useState('');
return (
<div>
<MyInput
value={value}
onChange={event => setValue(event.target.value)}
/>
</div>
);
};
For MUI V5
Moved your custom-styled code outside the component
For example:
import React from 'react';
import { useTheme, TextField, styled } from '#mui/material';
import { SearchOutlined } from '#mui/icons-material';
interface SearchInputProps { placeholder?: string; onChange: (event: React.ChangeEvent<HTMLInputElement>) => void; value: string; dataTest?: string; }
const StyledSearchInput = styled(TextField)(({ theme }: any) => { return {
'& .MuiOutlinedInput-root': {
borderRadius: '0.625rem',
fontSize: '1rem',
'& fieldset': {
borderColor: `${theme.palette.text.secondary}`
},
'&.Mui-focused fieldset': {
borderColor: `${theme.palette.primary}`
}
} }; });
const SearchInput: React.FC<SearchInputProps> = ({ placeholder = 'Search...', onChange, value, dataTest, ...props }) => { const theme = useTheme();
return (
<StyledSearchInput
{...props}
onChange={onChange}
placeholder={placeholder}
variant="outlined"
value={value}
inputProps={{ 'data-testid': dataTest ? dataTest : 'search-input' }}
InputProps={{
startAdornment: (
<SearchOutlined
sx={{ color: theme.palette.text.secondary, height: '1.5rem', width: '1.5rem' }}
/>
)
}}
/> ); };
export default SearchInput;
Be careful about your components' keys, if you set dynamic value as a key prop, it will also cause focus lost. Here is an example
{people.map(person => (
<div key={person.name}>
<Input type="text" value={person.name} onChange={// function which manipulates person name} />
</div>
))}

pass a data from a react component to another component which are on different routes

I have a CountryList react component
import React from "react";
import { Link } from "react-router-dom";
import { BsSearch } from "react-icons/bs";
export default function CountryList({
countries,
}: {
countries: any;
}): JSX.Element {
const [filter, setFilter] = React.useState("");
const [sortType, setSortType] = React.useState("");
console.log(filter);
const sorted = countries.sort((a: { name: string }, b: { name: any }) => {
const isReversed = sortType === "asc" ? 1 : -1;
return isReversed * a.name.localeCompare(b.name);
});
const onSort = (sortType: React.SetStateAction<string>) => {
console.log("changed");
setSortType(sortType);
};
return (
<div style={{ marginTop: "3rem" }}>
<div
style={{
display: "flex",
justifyContent: "space-between",
marginBottom: "10px",
}}
>
<div>List of countries</div>
<div style={{ display: "flex", alignItems: "center" }}>
<div style={{ position: "relative", marginRight: "1rem" }}>
<input
type="text"
placeholder="Filter"
name="namePrefix"
style={{ padding: "0.35rem" }}
onChange={(e: any) => {
setFilter(e.target.value);
}}
/>
<div style={{ position: "absolute", top: "5px", right: "5px" }}>
<BsSearch size="16" />
</div>
</div>
<div style={{ width: "8rem" }}>
<div className="btn-group">
<button
type="button"
className="btn dropdown-toggle sort-button"
data-bs-toggle="dropdown"
aria-expanded="false"
>
{sortType === "asc"
? "Ascending"
: sortType === "desc"
? "Descending"
: "Select"}
</button>
<ul className="dropdown-menu sort-button">
<li>
<button
className="dropdown-item"
type="button"
onClick={() => onSort("asc")}
>
Ascending
</button>
</li>
<li>
<button
className="dropdown-item"
type="button"
onClick={() => onSort("desc")}
>
Descending
</button>
</li>
</ul>
</div>
</div>
</div>
</div>
<div className="country-list-items">
{countries &&
sorted.map((item: any, index: number) => (
<div key={index}>
<Link style={{ display: "block" }} to={`/regions`}>
{item.name}
</Link>
</div>
))}
</div>
<div
style={{ marginTop: "20px", display: "flex", justifyContent: "center" }}
>
{countries && countries.length > 10 ? (
<button className="secondary-button">Load More</button>
) : (
<p>There are no more countries</p>
)}
</div>
</div>
);
}
Now from this component I need to pass the data of selected country id while the user clicks on the Link of the respective country, which I will be able to get by {item.code}. Also on clicking the Link the user will be redirected to /regions route where the list of regions of the selected country from this component will be shown. This is the RegionList Component:
import React from "react";
import { Link } from "react-router-dom";
import { BsSearch } from "react-icons/bs";
export default function RegionList(): JSX.Element {
return (
<div style={{ marginTop: "3rem" }}>
<div
style={{
display: "flex",
justifyContent: "space-between",
marginBottom: "10px",
}}
>
<div>List of regions</div>
<div style={{ display: "flex", alignItems: "center" }}>
<div style={{ position: "relative", marginRight: "1rem" }}>
<input
type="text"
placeholder="Filter"
style={{ padding: "0.35rem" }}
/>
<div style={{ position: "absolute", top: "5px", right: "5px" }}>
<BsSearch size="16" />
</div>
</div>
<div style={{ width: "8rem" }}>
<select name="sort" id="sort">
<option value="asc">Ascending</option>
<option value="desc">Descending</option>
</select>
</div>
</div>
</div>
<div className="country-list-items">
<div>
<Link style={{ display: "block" }} to={`/cities`}>
Alaska
</Link>
</div>
</div>
<div
style={{ marginTop: "20px", display: "flex", justifyContent: "center" }}
>
<button className="secondary-button">Load More</button>
<p>There are no more countries</p>
</div>
</div>
);
}
I need to pass the country id from the CountryList component to this RegionList component because I will do a GET network call in the RegionList component using the selected country id passed from the CountryList component. But I am not able to pass the country id data from CountryList component to RegionList component as they are on different routes and they do not have any common parent component. This is the route file for Countries
import { Route, Routes } from "react-router-dom";
import React from "react";
import CountryComponent from "../components/CountryComponent";
export class CountryRoute extends React.Component {
render() {
return (
<Routes>
<Route path="/" element={<CountryComponent />} />
</Routes>
);
}
}
here <CountryComponent /> is the mother component of CountryList
This is the route file for Regions:
import { Route, Routes } from "react-router-dom";
import React from "react";
import RegionComponent from "../components/RegionComponent";
export class RegionsRoute extends React.Component {
render() {
return (
<Routes>
<Route path="/" element={<RegionComponent />} />
</Routes>
);
}
}
here <RegionComponent /> is the mother component of RegionList
Here is the Main Component where all the components are called
import React from "react";
import { Routes, Route } from "react-router-dom";
import { ToastContainer } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";
import styled from "styled-components";
import "styled-components/macro";
import { CountryRoute } from "../country/route";
import { RegionsRoute } from "../region/route";
import { CitiesRoute } from "../cities/route";
const MainContainer = styled.div`
min-height: 100%;
margin: 5rem;
`;
export const Main = (): JSX.Element => {
return (
<>
<>
<MainContainer>
<div style={{ textAlign: "center" }}>
<b>GEO SOFTWARE</b>
</div>
<div>
<div>
<Routes>
<Route path={"/countries*"} element={<CountryRoute />} />
<Route path={"/regions*"} element={<RegionsRoute />} />
<Route path={"/cities*"} element={<CitiesRoute />} />
</Routes>
</div>
</div>
<ToastContainer
toastClassName={"toastContainer e-12"}
hideProgressBar
position="bottom-left"
closeButton={false}
autoClose={5000}
bodyClassName={"toastBody"}
/>
</MainContainer>
</>
</>
);
};
Now how can I pass the selected country code data from CountryList to the RegionList component.
You can use Query Params for this. In the CountryList you can use the Link like this:
<Link style={{ display: "block" }} to={`/regions?country=COUNTRY_ID`}>
Then in the RegionsList youn can get that Query Parameter from the url and use as you want.
Check this example https://reactrouter.com/web/example/query-parameters
You could set up a simple "store" to keep track of the selected country independently of your component hierarchy.
The simplest possible store
A stripped down, simplest implementation possible might look something like this:
const data = {}
export default {
setCountry: c => data.country = c,
getCountry: () => data.country
}
Because the "store" data is a singleton, any component that imports the store will get the same info, regardless of where it is in the component tree.
import store from './store';
export default () => (
<div>{store.getCountry()}</div>
)
Listening for changes, etc.
The example above omits some details that may be important, depending on what you're doing, like updating views that have already rendered when the country value changes.
If you need that sort of thing you could make the store an event emitter so your components can listen for updates:
import Emitter from 'events';
class CountryStore extends Emitter {
data = {}
getCountry () {
return this.data.country;
}
setCountry (c) {
this.data.country = c;
this.emit('change'); // notify interested parties of the change
}
}
export default new CountryStore();
With the emitter in place, components can register for change notifications when they mount:
import store from './store';
function SomeComponent () {
useEffect(() => {
store.on('change', () => {
// do stuff when store changes happen
}, [])
})
return (<div>...</div>)
}
Custom Hook
To make it easy to do this wherever its needed you could wrap it all up in a custom hook that handles it all and returns the current value and a setter [country, setCountry] just like useState would:
const useCountry = () => {
const [country, setCountry] = useState(store.getCountry());
const handler = () => setCountry(store.getCountry());
useEffect(() => {
store.on('change', handler);
return () => store.off('change', handler);
})
return [country, c => store.setCountry(c)];
}
Then your components have it easy:
import useCountry from './useCountry.js';
export default function SomeComponent () {
const [country, setCountry] = useCountry();
return (
<div>
<div>Current Country: {country}</div>
<button onClick={() => setCountry(Math.random())}>Change Country</button>
</div>
)
}
There are off-the-shelf libraries that will do all of this and more for you, but I thought it might be more helpful to explain an actual rudimentary implementation.
You can have some sort of global state country_id which is initially equal to null.
When user clicks on a country, set that country_id to be equal to the clicked country id.
Now, Inside you RegionList component you can access the country id through country_id state.
You can achieve the state management by different ways:
Prop drilling
Context API
Use Redux or Recoil to handle state-management
As others have pointed out, this is 100% what context is for.
It looks like this:
import React, { createContext, useContext } from 'react';
const MyCountryContext = createContext(null);
export const useCountry = () => useContext(MyCountryContext);
export const MyCountryContext = ({children}) => {
const [country,setCountry] = useState();
return (
<MyCountryContext.Provider value={[country,setCountry]}>
{children}
</MyCountryContext.Provider>
)
}
Use it like this:
export const Main = (): JSX.Element => {
return (
<MyCountryContext>
...rest of your tree
</MyCountryContext>
);
}
Then, in any components that are below MyCountryContext you can use the hook just like useState:
import { useCountry } from './MyCountryContext';
const MyComponentThatUsesCountry = () => {
const [country,setCountry] = useCountry();
return (...)
}

React How to conditionally override TextField error color in Material-UI?

I'm using React Material-UI library and I want to conditionally override the error color of a TextField.
I need to change the helperText, border, text and required marker color to yellow when the error is of a certain type. Something like that :
Otherwise, I want to keep the default color(red) for every other type of error.
I tried to follow the same principle used in this codesandbox but I couldn't get a grip of all the components that I needed to change and I had to use the important keyword almost every time to see a difference.
I have managed to conditionally change the color of the helperText like so :
<TextField
label="Name"
className={formClasses.textField}
margin="normal"
variant="outlined"
required
error={!!errors}
helperText={errors && "Incorrect entry."}
FormHelperTextProps={{classes: {root: getColorType(AnErrorType)}}}
/>
The getColorType will return a CSS object with the property color set to the one that corresponds the given error type. ex:
hardRequiredHintText: {
color: `${theme.palette.warning.light} !important`
},
Is there an easier way to override MUI error color and to see it reflected in all the component that uses it?
For each type of validation, display a different color, we can pass params to makeStyles
import { makeStyles } from "#material-ui/core/styles";
const useStyles = params =>
makeStyles(theme => ({
root: {
}
}));
const Component = () => {
const classes = useStyles(someParams)();
Full code:
import React from "react";
import "./styles.css";
import { TextField } from "#material-ui/core";
import { makeStyles } from "#material-ui/core/styles";
const useStyles = value =>
makeStyles(theme => ({
root: {
"& .Mui-error": {
color: acquireValidationColor(value)
},
"& .MuiFormHelperText-root": {
color: acquireValidationColor(value)
}
}
}));
const acquireValidationColor = message => {
switch (message) {
case "Incorrect entry":
return "green";
case "Please input":
return "orange";
default:
return "black";
}
};
const ValidationTextField = ({ helperText }) => {
const classes = useStyles(helperText)();
return (
<TextField
label="Name"
margin="normal"
variant="outlined"
required
error={helperText !== ""}
helperText={helperText}
className={classes.root}
/>
);
};
export default function App() {
const data = ["Incorrect entry", "Please input", ""];
return (
<div className="App">
{data.map((x, idx) => (
<ValidationTextField helperText={x} key={idx} />
))}
</div>
);
}
For Class Based Components
import React from "react";
import { TextField } from "#material-ui/core";
import { withStyles, createStyles } from "#material-ui/core/styles";
const commonStyles = (theme) =>
createStyles({
root: {},
warningStyles: {
"& .MuiFormLabel-root.Mui-error": {
color: "orange !important"
},
"& .MuiInput-underline.Mui-error:after": {
borderBottomColor: "orange !important"
},
"& .MuiFormHelperText-root.Mui-error": {
color: "orange !important"
}
}
});
class DemoComponent extends React.Component {
render() {
const { classes } = this.props;
const _text1HasWarning = false;
const _text2HasWarning = true;
const _text3HasWarning = false;
return (
<>
<TextField
error={false}
className={_text1HasWarning ? classes.warningStyles : null}
value="Valid Value"
variant="standard"
label="Valid label"
helperText="Valid helper text"
/>
<br />
<br />
<br />
<TextField
error={true}
className={_text2HasWarning ? classes.warningStyles : null}
value="warning value"
variant="standard"
label="warning label"
helperText="warning helper text"
/>
<br />
<br />
<br />
<TextField
error={true}
className={_text3HasWarning ? classes.warningStyles : null}
value="error value"
variant="standard"
helperText="error helper text"
label="error label"
/>
</>
);
}
}
export default withStyles(commonStyles)(DemoComponent);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
Output
You can accomplish this by overriding your Material-UI theme default styles and then wrapping your text field or your component inside of myTheme
import { createMuiTheme } from 'material-ui/styles';
const myTheme = createMuiTheme({
overrides:{
MuiInput: {
underline: {
'&:after': {
backgroundColor: 'any_color_value_in_hex',
}
},
},
}
});
export default myTheme;
and then import it into your component and use:
import {MuiThemeProvider} from 'material-ui/styles';
import myTheme from './components/myTheme'
<MuiThemeProvider theme = {myTheme}>
<TextField />
</MuiThemeProvider>
I hope it helps you.

React antd carousel methods

I am looking at using the antd Carousel, but I've not seen an example that describes how to use goTo(slideNumber, dontAnimate) method.
I have tried to use answers on this question react.js antd carousel with arrows to make goTo method works for me, but it didn't help, I always get carousel ref as null
import * as React from 'react';
import { createPortal } from 'react-dom';
import { Modal, Carousel } from 'antd'
export default class ImagePreviewCarousel extends React.Component<any, any> {
carousel = React.createRef();
componentDidMount() {
console.log(this.carousel);
}
render() {
const { url, imgList } = this.props;
const orderLayout = document.getElementById('order-layout');
const applicationLayout = document.getElementById('application');
return (
createPortal(<ImageViewer url={url} onClose={this.props.onClose} imgList={imgList} />, orderLayout || applicationLayout)
)
}
}
const ImageViewer = (props: IProps) => {
return (
<Modal
footer={null}
visible={props.onClose}
onCancel={props.onClose}
bodyStyle={{ backgroundColor: '#000' }}
width={'800px'}
>
<div style={{
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
marginTop: 'auto',
marginBottom: 'auto',
width: '100%',
height: '100%',
zIndex: 10
}}>
<Carousel ref={node => (this.carousel = node)}>
{props.imgList}
</Carousel>
</div>
</Modal>
);
}
result of console.log(this.carousel) always returns null, what am i doing wrong?
p.s react version 16.4.1,
antd Carousel is an implementation of react-slick, you can check its API example.
Here is my example using hooks:
import React, { useRef, useState } from 'react';
import { Carousel, Row, InputNumber } from 'antd';
function App() {
const [slide, setSlide] = useState(0);
const slider = useRef();
return (
<div>
<Row style={{ marginBottom: 10 }}>
<InputNumber
min={0}
max={3}
value={slide}
onChange={e => {
setSlide(e);
slider.current.goTo(e);
}}
/>
</Row>
<Row>
<Carousel
dots={false}
ref={ref => {
console.log(ref);
slider.current = ref;
}}
>
<div>
<h3>0</h3>
</div>
<div>
<h3>1</h3>
</div>
</Carousel>
</Row>
</div>
);
}
You need to pass ref to your child component like,
<ImageViewer url={url} onClose={this.props.onClose} imgList={imgList} onRef={this.carousel} />
And can access in child component like,
<Carousel ref={props.onRef}>
{props.imgList}
</Carousel>
While printing in componentDidMount,
componentDidMount() {
console.log(this.carousel); // If this gives you ref object
console.log(this.carousel.current); //This will give you element
console.log(this.carousel.current.value); //This will give you element's value if element has value.
}
Simplified Demo using input.

React native - Maximum call stack size exceeded

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',
}
})
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.

Categories