I am trying to use Victory for my React project but it is not working for some reason.
The code I am using is:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
data: this.getData()
};
}
componentDidMount() {
this.setStateInterval = window.setInterval(() => {
this.setState({
data: this.getData()
});
}, 3000);
}
componentWillUnmount() {
window.clearInterval(this.setStateInterval);
}
getData() {
const bars = random(6, 10);
return range(bars).map((bar) => {
return {x: bar + 1, y: random(2, 10)};
});
}
render() {
return (
<VictoryChart
domainPadding={{ x: 20 }}
animate={{duration: 500}}
>
<VictoryBar
data={this.state.data}
style={{
data: { fill: "tomato", width: 12 }
}}
animate={{
onExit: {
duration: 500,
before: () => ({
_y: 0,
fill: "orange",
label: "BYE"
})
}
}}
/>
</VictoryChart>
);
}
}
ReactDOM.render(<App/>, mountNode)
where I have used most components in different parts of my function.
The error I am getting is:
Line 28:18: 'random' is not defined no-undef
Line 29:12: 'range' is not defined no-undef
Line 30:30: 'random' is not defined no-undef
Search for the keywords to learn more about each error.
I don't know what to import as I have just added the Victory components
Here's an alternate function to the one you were using, it wasn't valid javascript. Where'd you get it from?
const getData = () => {
let arr = [];
for (let i = 0; i < 15; i++) {
arr.push({ x: x[i], y: y[Math.random(2, 10)] });
}
return arr;
};
Related
I'm trying to make a simple game: country flags are flashing one by one on the screen, and it stops on one particular flag after clicking on the button.
This is what I have so far:
import React from 'react'
import ReactDOM from 'react-dom'
// CSS styles in JavaScript Object
const buttonStyles = {
backgroundColor: '#61dbfb',
padding: 10,
border: 'none',
borderRadius: 5,
margin: 30,
cursor: 'pointer',
fontSize: 18,
color: 'white',
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = { image: 'https://www.countryflags.io/US/shiny/64.png' }
this.makeTimer()
}
makeTimer() {
setInterval(() => {
let countries = {
USA: 'https://www.countryflags.io/US/shiny/64.png',
Australia: 'https://www.countryflags.io/AU/shiny/64.png',
"Puerto Rico": 'https://www.countryflags.io/PR/shiny/64.png'
}
let currentCountry = Math.floor(Math.random() * (Object.entries(countries).map(([key, value]) => <div>{key} <img alt={key} src={value}></img></div>)))
this.setState({ currentCountry })
}, 1000)
}
stopInterval = () => {
clearInterval(this.interval);
}
render() {
return (
<div className='app'>
<h1>where are you going on vacation?</h1>
<div>{this.state.currentCountry}</div>
<button style={buttonStyles} onClick={this.stopInterval}> choose country </button>
</div>
)
}
}
const rootElement = document.getElementById('root')
ReactDOM.render(<App />, rootElement)
It does not work, all that renders is:
NaN
Before I added Math.floor(Math.random() * ...) it rendered all three flags at the same time, which is not what I want. Where is the mistake?
Also, I am not sure if the timer works correctly.
You can't multiply a number (Math.random) with an array (Object.entries(countries).map).
You should create a helper function to grab a single element (or value) from an object if you're storing the flags in an object.
Also, you should never ever store JSX elements in your state. All you need is a URL, not a whole image element. You can store a random URL and update the image's src if the state is updated:
const buttonStyles = {
backgroundColor: '#61dbfb',
border: 'none',
borderRadius: 5,
color: 'white',
cursor: 'pointer',
fontSize: 18,
margin: 30,
padding: 10,
};
function randomProperty(obj) {
const keys = Object.keys(obj);
return obj[keys[(keys.length * Math.random()) << 0]];
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
currentCountry: null,
image: 'https://flagcdn.com/w128/us.png',
};
this.makeTimer();
}
makeTimer() {
let countries = {
'Australia': 'https://flagcdn.com/w160/au.png',
'Puerto Rico': 'https://flagcdn.com/w160/pr.png',
'USA': 'https://flagcdn.com/w160/us.png',
};
this.interval = setInterval(() => {
let currentCountry = randomProperty(countries);
this.setState({ currentCountry });
}, 1000);
}
stopInterval = () => {
clearInterval(this.interval);
};
render() {
return (
<div className="app">
<h1>Where are you going on vacation?</h1>
<img alt="" src={this.state.currentCountry} width="80" />
<button style={buttonStyles} onClick={this.stopInterval}>
Choose country
</button>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('root'));
<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>
<div id="root"></div>
I got something different for you, I expect it helps you.
let countries = {
USA: 'https://www.countryflags.io/US/shiny/64.png',
Australia: 'https://www.countryflags.io/AU/shiny/64.png',
'Puerto Rico': 'https://www.countryflags.io/PR/shiny/64.png',
};
//I changed the object to array for better data manipulation.
const countriesArray = Object.entries(countries).map(country => {
return { name: country[0], flag: country[1] }
})
//Getting random country index by its length
const randomCountryIndex = Math.floor(Math.random() * countriesArray.length);
console.log("Set the current country: ", countriesArray[randomCountryIndex])
console.log("Set the random flag: ", countriesArray[randomCountryIndex].flag)
So after this you can check if user's answers match the current country on state
Avoid jsx in state.
Refactored your Math.random() code.
import React from 'react'
import ReactDOM from 'react-dom'
const countries = [
{ name: "USA", image: 'https://www.countryflags.io/US/shiny/64.png' },
{ name: "Australia", image: 'https://www.countryflags.io/AU/shiny/64.png'},
{ name: "Puerto Rico", image: 'https://www.countryflags.io/PR/shiny/64.png' }
];
// CSS styles in JavaScript Object
const buttonStyles = {
backgroundColor: '#61dbfb',
padding: 10,
border: 'none',
borderRadius: 5,
margin: 30,
cursor: 'pointer',
fontSize: 18,
color: 'white',
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = { image: 'https://www.countryflags.io/US/shiny/64.png' }
this.makeTimer()
}
makeTimer() {
this.interval = setInterval(() => {
const countryIndex = Math.floor(Math.random() * countries.length);
this.setState({
image: countries[countryIndex].image
});
}, 1000)
}
stopInterval = () => {
clearInterval(this.interval);
}
render() {
return (
<div className='app'>
<h1>where are you going on vacation?</h1>
<div>{this.state.currentCountry}</div>
<button style={buttonStyles} onClick={this.stopInterval}> choose country </button>
</div>
)
}
}
const rootElement = document.getElementById('root')
ReactDOM.render(<App />, rootElement)
Math.floor(Math.random()) returns zero!
use this:
Math.floor(Math.random() * 10);
I am trying to be able to use cntrl+s while focus within a textarea using react-hotkeys.
this.keyMap = {
KEY: "ctrl+s"
};
this.handlers = {
KEY: (e) => {
e.preventDefault();
this.saveBtn(c);
}
};
<HotKeys keyMap={this.keyMap} handlers={this.handlers}>
<textarea/>
</HotKeys>
You need to use Control+s, not ctrl+s.
You need to call configure like that so it won't ignore textareas:
import { configure } from "react-hotkeys";
configure({
ignoreTags: []
});
Following is not solution it's work around but it fulfills the requirement...
[Please Note] Basically I have restricted access to Ctrl key in browser and then it
works fine though.
import { HotKeys } from 'react-hotkeys';
import React, { PureComponent, Component } from 'react';
import { configure } from 'react-hotkeys';
const COLORS = ['green', 'purple', 'orange', 'grey', 'pink'];
const ACTION_KEY_MAP = {
KEY: 'Control+s',
};
class Login extends Component {
constructor(props, context) {
super(props, context);
this.changeColor = this.changeColor.bind(this);
configure({
ignoreTags: ['div']
});
this.state = {
colorNumber: 0
};
}
changeColor(e) {
e.preventDefault();
this.setState(({ colorNumber }) => ({ colorNumber: colorNumber === COLORS.length - 1 ? 0 : colorNumber + 1 }));
}
KeyDown(e){
if(e.ctrlKey) e.preventDefault();
}
render() {
const handlers = {
KEY: this.changeColor
};
const { colorNumber } = this.state;
const style = {
width: 200,
height: 60,
left: 20,
top: 20,
opacity: 1,
background: COLORS[colorNumber],
};
return (
<HotKeys
keyMap={ACTION_KEY_MAP}
handlers={handlers}
>
<textarea
style={style}
className="node"
tabIndex="0"
onKeyDown={this.KeyDown}
></textarea>
</HotKeys>
);
}
}
export default Login;
Every element of the array should be displayed for some time and the time for which each element is displayed should be determined by a value in each element.
let array=[{display:"a",time:10},{display:"b",time:15},{display:"c",time:22}]
class App extends React.Component{
state={stateDisplay:"",
stateTime:""
}
componentWillMount(){
var i=0;
let handle=setInterval(()=>{
var element= array[i]
this.setState({
stateDisplay:element.display,
stateTime:element.time,
})
i=i+1;
if(i===array.length){
clearInterval(handle)
}
},10000)
}
render(){
return(
<div> {this.state.stateDisplay} </div>
)}}
i have done something like this but using setinterval the delay can only be set for a constant time,here 10s.
I want the first element to display for 10s and then the next element for 15s, third for 22s which is the time value for each element of the array.
I know i cant do that using setinterval is there a way to do this using Settimeout?
This was almost like a little challenge, heres what i managed to come up with, its in typescript, if you need js, just remove interfaces and type annotations
/* eslint-disable #typescript-eslint/no-explicit-any */
/* eslint-disable prettier/prettier */
/* eslint-disable no-shadow */
/* eslint-disable no-console */
import React, { FC, useState, useEffect, useCallback } from 'react';
import { View, Button, Text } from 'react-native';
interface Data {
duration: number;
bgColor: string;
}
const dataArr: Data[] = [
{ duration: 3, bgColor: 'tomato' },
{ duration: 6, bgColor: 'skyblue' },
{ duration: 9, bgColor: 'gray' },
];
const Parent = () => {
const [currentIdx, setCurrentIdx] = useState<number>(0);
const [elementData, setElementData] = useState<Data>(dataArr[currentIdx]);
useEffect(() => {
console.log('idx', currentIdx);
if (currentIdx > dataArr.length) return;
setElementData({ ...dataArr[currentIdx] });
}, [currentIdx]);
const pushNext = () => {
setCurrentIdx(currentIdx + 1);
};
const handleRestart = () => {
setCurrentIdx(0);
setElementData({ ...dataArr[0] });
};
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Timer
data={elementData}
onCountDownComplete={pushNext}
restart={handleRestart}
/>
</View>
);
};
interface Props {
data: Data;
onCountDownComplete: () => void;
restart: () => void;
}
const Timer: FC<Props> = ({ data, onCountDownComplete, restart }) => {
const [seconds, setSeconds] = useState<number>(data.duration);
// update on data change
useEffect(() => {
setSeconds(data.duration);
}, [data]);
const callback = useCallback(() => {
onCountDownComplete();
}, [onCountDownComplete]);
useEffect(() => {
let interval: any = null;
if (seconds > -1) {
interval = setInterval(() => {
if (seconds - 1 === -1) {
callback();
} else {
setSeconds(seconds - 1);
}
}, 1000);
} else {
return;
}
return () => {
clearInterval(interval);
};
}, [seconds, callback]);
return (
<View
style={{ backgroundColor: data.bgColor, padding: 16, borderRadius: 10 }}
>
<Text style={{ marginBottom: 24 }}>{seconds}</Text>
<Button title="restart" onPress={restart} />
</View>
);
};
Using react-native, I'm creating sub-Components within the parent App and providing their position to the array this.state.objLocation within the parent App.
I can get the initial location data into the array straight after the render, but because my subcomponents are draggable, each time they re-render on drag, it adds a new position object to the array.
I'd like to avoid this, and I thought that creating this.state = { firstRender: true } in the constructor and then using componentDidMount = () => { this.setState({ firstRender: false }) } after the first render would allow me to create a 'gate' to stop the addition of the extra position objects.
I can see that if I comment out //componentDidMount = () => { this.setState({ firstRender: false }) } then I will get multiple entries to my array but if it's included in the class I get absolutely none.
So possibly my interpretation of the render lifecycle and componentDidMount is incorrect?
Here is my code.
// App
import React, { Component } from 'react';
import { View, Text, } from 'react-native';
import styles from './cust/styles';
import Draggable from './cust/draggable';
const dataArray = [{num: 1,id: 'A',},{num: 2,id: 'B',},{num: 3,id: 'Z',}]
export default class Viewport extends Component {
constructor(props){
super(props);
this.state = {
dID : null,
objLocation: [],
firstRender: true,
};
}
render(){
return (
<View style={styles.mainContainer}>
<View style={styles.draggableContainer}>
<Text>Draggable Container</Text> {dataArray.map( d => { return(
<Draggable
id={d.id}
onLayout={ e=> this.onLayout(e)}
onPanResponderGrant={(dID) =>this.setState({ dID })}
onPanResponderRelease={() => this.setState({dID: null})} /> ) })}
<View style={[styles.findPoint ]} />
</View>
<View style={styles.infoBar}>
<Text>{this.state.dID ? this.state.dID : ''}</Text>{this.compFrame()}
</View>
</View>
);
}
onLayout = (e) => {
if ( e && this.state.firstRender) {
const n = e.nativeEvent.layout;
const position = {
width: n.width,
height: n.height,
x: n.x,
y: n.y
}
console.log(position);
this.setState({
objLocation: this.state.objLocation.concat([position])
});
}
}
componentWillMount = () => {
console.log("START");
}
compFrame = () => {
return(
this.state.objLocation.map( d => {<View style={[styles.findPoint2,{left: d.x, top: d.y, width: d.width, height: d.height} ]} ></View>})
)
}
componentDidMount = () => {
this.setState({firstRender: true })
console.log(this.state.objLocation.length);
}
}
// Draggable
import React, { Component } from 'react';
import { Text, PanResponder, Animated } from 'react-native';
import styles from './styles';
class Draggable extends Component {
constructor(props) {
super(props);
this.state = {
pan: new Animated.ValueXY(),
};
this.panResponder = PanResponder.create({
onStartShouldSetPanResponder: () => true,
onPanResponderGrant: () => {
this.props.onPanResponderGrant(this.props.id);
},
onPanResponderMove: Animated.event([ null, {
dx: this.state.pan.x,
dy: this.state.pan.y,
},
]),
onPanResponderRelease: () => {
Animated.spring(this.state.pan, { toValue: { x: 0, y: 0 } }).start();
this.props.onPanResponderRelease();
},
});
}
render() {
return (
<Animated.View
onLayout={ (e) => this.props.onLayout(e) }
{...this.panResponder.panHandlers}
style={[this.state.pan.getLayout(), styles.circleAlt, styles.position]}>
<Text style={styles.textAlt}>Drag me!</Text>
<Text style={styles.textNum}>{this.props.id}</Text>
</Animated.View>
);
}
componentDidMount = () => {
this.props.onLayout(this.props.dragEvent)
}
}
export default Draggable;
// Output of console.log
START xxx
0
{width:108,height:108,x:133.5,y:376.5}
{width:108,height:108,x:133.5,y:78.5}
{width:108,height:108,x:133.5,y:227.5}
You could set the firstRender state in onLayout function
onLayout = (e) => {
if ( e && this.state.firstRender) {
const n = e.nativeEvent.layout;
const position = {
width: n.width,
height: n.height,
x: n.x,
y: n.y
}
console.log(position);
this.setState({
firstRender: false,
objLocation: this.state.objLocation.concat([position])
});
}
}
According to the information provided by you, your onLayout function is called by the component so its not included in the component lifecycle process, so when the component completes its lifecycle it goes into componentDidMount after mounting (which is not calling onLayout func) & thus changed the firstRender state to false and hence when you drag the component each time it goes from true to false.
I hope this explains
I feel like I've hacked this, to get it to work, so please correct me as to correct procedure.
This is the onLayout method from the App. I've included an if statement that checks if the new positions array length is equal too the dataArray length that the draggable items are based on.
It looks like this.
onLayout = (e) => {
if ( this.state.objLocation.length != dataArray.length ) {
if ( e ) {
const n = e.nativeEvent.layout;
const position = {
width: n.width,
height: n.height,
x: n.x,
y: n.y
}
console.log(position);
this.setState({
objLocation: this.state.objLocation.concat([position])
});
}
}
}
Working with React-Native and trying to learn ES6 syntax. I had a similar issue yesterday and got the solution. I added
.bind(this)
to my my function calls and the problem was solved. I ran into the same issue again with another function call and I cannot track down what is going on. The error message is the same.
undefined is not a object (evaluating 'this.props.drawer.open')
The function is:
onClickMenu () {
this.props.drawer.open();
}
and it is being called with this:
onPress={this.onClickMenu.bind(this)}
Here is the entire code. If you see something other than this issue that doesn't look right let me know please! *note I have replaced "var" with "let". From what I've read it is proper ES6 syntax to do that everywhere?
'use strict';
const React = require('react-native');
const {
Text,
View,
Component,
StyleSheet,
SwitchAndroid
} = React;
import { Button } from 'react-native-material-design';
import Store from 'react-native-simple-store';
import Underscore from 'underscore';
import RNGMap from 'react-native-gmaps';
import Polyline from 'react-native-gmaps/Polyline';
import Icon from 'react-native-vector-icons/Ionicons';
import SettingsService from './../settings/settings.service';
//import subdivisions from './subdivisions.json';
import commonStyles from './../common/styles';
let accessToken = null;
let userId = null;
let routeId = null;
let subdivisionId = null;
SettingsService.init('Android');
class Map extends Component {
constructor(props) {
super(props)
this.state = {
odometer: 0,
mapWidth: 300,
mapHeight: 300,
enabled: false,
isMoving: false,
currentLocation: undefined,
locationManager: undefined,
paceButtonIcon: 'Start Trip',
navigateButtonIcon: 'navigate',
paceButtonStyle: commonStyles.disabledButton,
// mapbox
center: {
lat: 40.7223,
lng: -73.9878
},
zoom: 10,
markers: []
}
}
componentDidMount() {
Store.get('token').then((token) => {
accessToken = token.access_token;
userId = token.userId;
});
let me = this,
gmap = this.refs.gmap;
this.locationManager = this.props.locationManager;
// location event
this.locationManager.on("location", function(location) {
console.log('- location: ', JSON.stringify(location));
me.setCenter(location);
gmap.addMarker(me._createMarker(location));
me.setState({
odometer: (location.odometer / 1000).toFixed(1)
});
// Add a point to our tracking polyline
if (me.polyline) {
me.polyline.addPoint(location.coords.latitude, location.coords.longitude);
}
});
// http event
this.locationManager.on("http", function(response) {});
// geofence event
this.locationManager.on("geofence", function(geofence) {});
// error event
this.locationManager.on("error", function(error) {
console.log('- ERROR: ', JSON.stringify(error));
});
// motionchange event
this.locationManager.on("motionchange", function(event) {
me.updatePaceButtonStyle();
});
// getGeofences
this.locationManager.getGeofences(function(rs) {
}, function(error) {
console.log("- getGeofences ERROR", error);
});
SettingsService.getValues(function(values) {
values.license = "eddbe81bbd86fa030ea466198e778ac78229454c31100295dae4bfc5c4d0f7e2";
values.orderId = 1;
values.stopTimeout = 0;
//values.url = 'http://192.168.11.120:8080/locations';
me.locationManager.configure(values, function(state) {
me.setState({
enabled: state.enabled
});
if (state.enabled) {
me.initializePolyline();
me.updatePaceButtonStyle()
}
});
});
this.setState({
enabled: false,
isMoving: false
});
}
_createMarker(location) {
return {
title: location.timestamp,
id: location.uuid,
icon: require("image!transparent_circle"),
anchor: [0.5, 0.5],
coordinates: {
lat: location.coords.latitude,
lng: location.coords.longitude
}
};
}
initializePolyline() {
// Create our tracking Polyline
let me = this;
Polyline.create({
width: 12,
points: [],
geodesic: true,
color: '#2677FF'
}, function(polyline) {
me.polyline = polyline;
});
}
onClickMenu () {
this.props.drawer.open();
}
onClickEnable() {
let me = this;
if (!this.state.enabled) {
this.locationManager.start(function() {
me.initializePolyline();
});
} else {
this.locationManager.resetOdometer();
this.locationManager.stop();
this.setState({
markers: [{}],
odometer: 0
});
this.setState({
markers: []
});
if (this.polyline) {
this.polyline.remove(function(result) {
me.polyline = undefined;
});
}
}
this.setState({
enabled: !this.state.enabled
});
this.updatePaceButtonStyle();
}
onClickPace() {
if (!this.state.enabled) {
return;
}
let isMoving = !this.state.isMoving;
this.locationManager.changePace(isMoving);
this.setState({
isMoving: isMoving
});
this.updatePaceButtonStyle();
}
onClickLocate() {
let me = this;
this.locationManager.getCurrentPosition({
timeout: 30
}, function(location) {
me.setCenter(location);
}, function(error) {
console.error('ERROR: getCurrentPosition', error);
me.setState({
navigateButtonIcon: 'navigate'
});
});
}
onRegionChange() {}
setCenter(location) {
this.setState({
navigateButtonIcon: 'navigate',
center: {
lat: location.coords.latitude,
lng: location.coords.longitude
},
zoom: 16
});
}
onLayout() {
let me = this,
gmap = this.refs.gmap;
this.refs.workspace.measure(function(ox, oy, width, height, px, py) {
me.setState({
mapHeight: height,
mapWidth: width
});
});
}
updatePaceButtonStyle() {
let style = commonStyles.disabledButton;
if (this.state.enabled) {
style = (this.state.isMoving) ? commonStyles.redButton : commonStyles.greenButton;
}
this.setState({
paceButtonStyle: style,
paceButtonIcon: (this.state.enabled && this.state.isMoving) ? 'Stop Trip' : 'Start Trip'
});
}
render() {
return (
<View style={commonStyles.container}>
<View style={commonStyles.topToolbar}>
<Icon.Button name="android-options" onPress={this.onClickMenu.bind(this)} backgroundColor="transparent" size={30} color="#000" style={styles.btnMenu} underlayColor={"transparent"} />
<Text style={commonStyles.toolbarTitle}>Background Geolocation</Text>
<SwitchAndroid onValueChange={this.onClickEnable.bind(this)} value={this.state.enabled} />
</View>
<View ref="workspace" style={styles.workspace} onLayout={this.onLayout.bind(this)}>
<RNGMap
ref={'gmap'}
style={{width: this.state.mapWidth, height: this.state.mapHeight}}
markers={this.state.markers}
zoomLevel={this.state.zoom}
onMapChange={(e) => console.log(e)}
onMapError={(e) => console.log('Map error --> ', e)}
center={this.state.center} />
</View>
<View style={commonStyles.bottomToolbar}>
<Icon.Button name={this.state.navigateButtonIcon} onPress={this.onClickLocate.bind(this)} size={25} color="#000" underlayColor="#ccc" backgroundColor="transparent" style={styles.btnNavigate} />
<Text style={{fontWeight: 'bold', fontSize: 18, flex: 1, textAlign: 'center'}}>{this.state.odometer} km</Text>
<Button raised={true}
text={this.state.paceButtonIcon}
onPress={this.onClickPace.bind(this)}
overrides={{backgroundColor:"#e12429",textColor:"#ffffff"}}
style={this.state.paceButtonStyle}></Button>
<Text> </Text>
</View>
</View>
);
}
};
const styles = StyleSheet.create({
workspace: {
flex: 1
}
});
module.exports = Map;
UPDATE:
debugging via adb in the terminal shows the same error
So here is rest of code. to troubleshoot. I added the project files to a plunker. it is a demo project that i am working with. plunker
'use strict';
const React = require('react-native');
const {
Text,
Component,
StyleSheet,
AppRegistry
} = React;
import Map from './map/map';
import Drawer from 'react-native-drawer';
import Settings from './settings/settings.android';
import Icon from 'react-native-vector-icons/Ionicons';
import BackgroundGeolocation from 'react-native-background-geolocation-android';
global.bgGeo = BackgroundGeolocation;
class App extends Component {
onClickMenu() {
this.props.refs.drawer.open();
}
render() {
return (
<Drawer ref="drawer" side="right" acceptPan={false} content={<Settings drawer={this.refs.drawer} locationManager={BackgroundGeolocation} />}>
<Map drawer={this.refs.drawer} locationManager={BackgroundGeolocation} />
</Drawer>
);
}
};
module.exports = App;
UPDATE:
I dont think you can pass through refs to components in such a way,
certainly it would not work in React and I dont think it would work
in such a way in React-Native either.
I'm not clear why you are trying to .open the Drawer from the
Map component as it looks like the Map component can only be
accessed when the Drawer is open, but, if you want to access parent
behaviours from children a good pattern is to pass through functions
for children to execute (you could argue that this is actually bad
and that passing events around is a more robust pattern).
I've never used the library so I'm not totally clear on its usage but
you can pass functions through like this:
class Application extends Component {
closeControlPanel = () => {
this.refs.drawer.close()
};
openControlPanel = () => {
this.refs.drawer.open()
};
render () {
return (
<Drawer
ref="drawer"
content={<ControlPanel />}
>
<Map onMenuClose={ this.closeControlPanel.bind( this ) } />
</Drawer>
)
}
})
In this case this.props.onMenuClose should be attached to an action, which, when executed will trigger the function from the parent and execute the this.refs.drawer.close function.