How to emit event to app root in react native - react-native

I'm trying to implement toast message (notification) on my React Native app.
I'm Thinking about implement my Toast component inside app root, and when a button is clicked (somewhere in the app), the app root will know about it and make the toast visible.
I don't want to use a library because I have complicated UI for this and I want to include buttons inside the toast.
This is the root component - App.js:
import { Provider } from 'react-redux';
import {Toast} from './src/components/Toast';
import store from './src/store/Store.js';
import AppNavigator from './src/navigation/AppNavigator';
import StatusBar from './src/components/StatusBar';
export default function App(props) {
return (
<Provider store = { store }>
<View style={styles.container}>
<StatusBar barStyle="default"/>
<AppNavigator />
<Toast></Toast>
</View>
</Provider>
);
}
EDIT:
AppNavigator.js:
// this is how I connect each page:
let HomePage = connect(state => mapStateToProps, dispatch => mapDispatchToProps(dispatch))(HomeScreen);
let SearchPage = connect(state => mapStateToProps, dispatch => mapDispatchToProps(dispatch))(SearchScreen);
const HomeStack = createStackNavigator(
{
Home: HomePage,
Search: SearchPage,
},
config
);
const mapStateToProps = (state) => {
return {
// State
}
};
const mapDispatchToProps = (dispatch) => {
return {
// Actions
}
};
export default tabNavigator;
Any ideas how can I do it? Thanks.

For this, i would suggest to use a component to wrap your application where you have your toast. For example:
App.js
render(){
return (
<Provider store = { store }>
<View style={styles.container}>
<AppContainer/>
</View>
</Provider>
)
}
Where your AppContainer would have a render method similar to this:
render(){
return (
<Frament>
<StatusBar barStyle="default"/>
<AppNavigator />
<Toast></Toast>
</Fragment>
)
}
Then (as you are using redux) you can connect your AppContainer. After that, just make this component aware of changes on redux using componentDidUpdate
componentDidUpdate = (prevProps) => {
if(this.props.redux_toast.visible !== prevProps.redux_toast.visible){
this.setState({
toastVisible : this.props.redux_toast.visible,
toastMessage: this.props.redux_toast.message
})
}
}
This is just an example on how it could be done by using redux, I don't know how your toast or redux structure is, but it should be an available solution for your use case.
EDIT.
This is how it should look like:
//CORE
import React from 'react';
//REDUX
import { Provider } from 'react-redux';
import store from './redux/store/store';
import AppContainer from './AppContainer';
export default () => {
return (
<Provider store={store}>
<AppContainer />
</Provider>
)
}
AppContainer.js:
import React, { Component } from "react";
import { View, Stylesheet } from "react-native";
import StatusBar from "path/to/StatusBar";
import AppNavigator from "path/to/AppNavigator";
import Toast from "path/to/Toast";
import { connect } from "react-redux";
class AppContainer extends Component {
constructor(props){
super(props);
this.state={
toastVisible:false,
toastMessage:""
}
}
componentDidUpdate = (prevProps) => {
if(this.props.redux_toast.visible !== prevProps.redux_toast.visible){
this.setState({
toastVisible : this.props.redux_toast.visible,
toastMessage: this.props.redux_toast.message
})
}
}
render(){
return (
<View style={styles.container}>
<StatusBar barStyle="default"/>
<AppNavigator />
<Toast visible={this.state.toastVisible}
message={this.state.toastMessage}
/>
</View>
)
}
}
const styles = StyleSheet.create({
container:{
flex:1
}
})
const mapStateToProps = state => ({ ...yourMapStateToProp })
const mapDispatchToProps = state => ({ ...mapDispatchToProps })
export default connect(mapStateToProps, mapDispatchToProps)(AppContainer)
Rest of the code remains untouched, you need to dispatch an action that changes a props that your appContainer's componentDidUpdate is listening to (in the example i called it redux_toast.visible).

Related

React native navigation not initialized yet

I'm learning react native but I'm having difficulty with navigation, it's returning the error that navigation has not been initialized yet.
I looked for some tutorials, I tried some other ways, I went to the react native navigation documentation and, incredible as it may seem, it's the same as in the documentation... not even the GPT chat haha ​​it didn't help me.
Can someone with experience in react native give me a light?
app.tsx:
import { NavigationContainer } from '#react-navigation/native';
import { createAppContainer } from 'react-navigation';
import StackNavigator from './app/index/navigator';
const AppContainer = createAppContainer(StackNavigator);
const App = () => {
return (
<NavigationContainer>
<AppContainer />
</NavigationContainer>
);
}
export default App;
navigator.tsx?
import { createStackNavigator } from 'react-navigation-stack';
import Index from '.';
import AddNewGrocery from '../components/addNewGrocery'
const StackNavigator = createStackNavigator({
home: { screen: Index, navigationOptions: { headerShown: false } },
addNewGrocery: { screen: AddNewGrocery, navigationOptions: { headerShown: false } },
});
export default StackNavigator;
index.tsx:
const Index = () => {
return (
<View style={styles.container}>
<Text style={styles.title}>Gestão de Compras</Text>
<LastFiveGrocery />
<MonthAverageSpend />
<TotalSpend />
<AddButton />
<StatusBar
translucent={false}
backgroundColor={'rgba(43, 43, 43, 1)'}
barStyle='light-content' />
</View>
);
}
AddButton.tsx:
import React from 'react';
import { StyleSheet, View, TouchableOpacity } from 'react-native';
import { Ionicons } from '#expo/vector-icons';
import { useNavigation } from '#react-navigation/native';
const AddButton = () => {
const navigation = useNavigation();
const handleAddButtonPress = () => {
navigation.navigate('addNewGrocery' as never);
}
return (
<TouchableOpacity style={styles.addButtonContainer} onPress={handleAddButtonPress}>
<View style={styles.addButton}>
<Ionicons name="ios-add" size={36} color="white" />
</View>
</TouchableOpacity>
);
}
I already tried to use it this way:
AddButton:
const { navigate } = useNavigation<StackNavigationProp<ParamListBase>>();
const handleAddButtonPress = () => {
navigate('addNewGrocery');
}
I've also tried using it this way:
navigator:
const StackNavigator = createAppContainer(createStackNavigator({
Home: { screen: Index },
addNewGrocery: AddNewGrocery,
}));
app.tsx:
import StackNavigator from './app/index/navigator';
const App = () => {
return (
<StackNavigator />
);
}
export default App;
You are using 2 different navigation library in simultaneously:
#react-navigation
react-navigation
Remove react-navigation and refactor the App.js file as below:
import { NavigationContainer } from '#react-navigation/native';
import StackNavigator from './app/index/navigator';
const App = () => {
return (
<NavigationContainer>
<StackNavigator />
</NavigationContainer>
);
}
export default App
StackNavigator should be implemented as per documentation -
https://reactnavigation.org/docs/stack-navigator/#api-definition

Navigation.getParam is undefined while trying to pass function as parameter

I'm trying to use a function from my Main component in my details component which I user react navigation to navigate to and I want to save some changes in detail screen in my main component
//Main.js
import React from 'react';
import {
StyleSheet ,
Text,
View,
TextInput,
ScrollView,
TouchableOpacity,
KeyboardAvoidingView,
AsyncStorage
} from 'react-native'
import Note from './Note'
import { createStackNavigator, createAppContainer } from "react-navigation";
import Details from './Details';
export default class Main extends React.Component {
static navigationOptions = {
title: 'To do list',
headerStyle: {
backgroundColor: '#f4511e',
},
};
constructor(props){
super(props);
this.state = {
noteArray: [],
noteText: ''
};
}
render() {
let notes = this.state.noteArray.map((val,key) => {
return <Note key={key} keyval={key} val={val}
goToDetailPage= {() => this.goToNoteDetail(key)}
/>
});
const { navigation } = this.props;
return(
<View style={styles.container}>
<ScrollView style={styles.scrollContainer}>
{notes}
</ScrollView>
<Details saveEdit={this.saveEdit} />
</View>
);
}
goToNoteDetail=(key)=>{
this.props.navigation.navigate('DetailsScreen', {
selectedTask: this.state.noteArray[key],
saveEdit: this.saveEdit
});
}
saveEdit = (editedTask,dueDate) => {
this.state.noteArray.push({
'creationDate': editedTask['creationDate'],
'taskName': editedTask['taskName'],
'dueDate': dueDate
});
this.setState({noteArray:this.state.noteArray})
this.saveUserTasks(this.state.noteArray)
}
this.setState({noteArray:this.state.noteArray})
this.saveUserTasks(this.state.noteArray)
}
}
Then I try to use it as prop in my Detail.js
import React from 'react';
import {
StyleSheet ,
Text,
View,
TextInput,
Button,
TouchableOpacity,
} from 'react-native'
import { createStackNavigator, createAppContainer } from "react-navigation";
export default class Details extends React.Component {
constructor(props){
super(props);
this.state = {
dueDate = ''
}
}
static navigationOptions = {
headerStyle: {
backgroundColor: '#f4511e',
},
};
componentDidMount = () => {
this.getUserTasks()
}
render() {
const { navigation } = this.props;
const selectedTask = navigation.getParam('selectedTask', 'task');
var { saveEdit} = this.props;
return(
<View key={this.props.keyval} style={styles.container}>
<View style = { styles.info}>
<Text style= {styles.labelStyle}> Due date:
</Text>
<TextInput
onChangeText={(dueData) => this.setState({dueData})}
style={styles.textInput}
placeholder= {selectedTask['dueDate']}
placeholderTextColor='gray'
underlineColorAndroid = 'transparent'
>
</TextInput>
</View>
<TouchableOpacity onPress={this.props.saveEdit(selectedTask, this.state.dueDate)} style={styles.saveButton}>
<Text style={styles.saveButtonText}> save </Text>
</TouchableOpacity>
</View>
);
}
}
I searched a lot to find the solution and I tried many of them but get different undefined errors. This is not what I did in the first place but when I search I found this solution here. And I know it causes lots of issues.
I want to know how can I manage to access to main method from details and pass parameters to it or how can I manage to use main props in my details component
If you are using react-navigation 5, params is no longer under the navigation object but under route object. This is the link to the sample code:
https://reactnavigation.org/docs/params
Solution
<Details saveEdit={this.saveEdit} />
to
<Details navigation={this.props.navigation} saveEdit={this.saveEdit} />
render() {
return(
<View style={styles.container}>
<ScrollView style={styles.scrollContainer}>
{notes}
</ScrollView>
<Details navigation={this.props.navigation} saveEdit={this.saveEdit} />
</View>
);
}
Why?
You are using your Details component in Main screen. So you need to give navigation to Details's props from your Main to use navigation props in Details component.
Because your Details component is not the screen component registered in your navigator(router).
I tried to run your code on my machine but it seems you have too many syntax error in your code (maybe because of copy pasta?)
but it seems you should change
<TouchableOpacity onPress={this.props.saveEdit(selectedTask, this.state.dueDate)}
in Detals.js to
<TouchableOpacity onPress={this.props.navigation.getParams('saveEdit')(selectedTask, this.state.dueDate)}
for clarification this worked for me
in MainPage.js
_test(){
console.log('test');
}
.
.
.
<ActionButton
buttonColor="rgba(231,76,60,1)"
onPress={() => NavigationService.navigate('AddNewSession', {test: this._test})}>
</ActionButton>
and in AddNewSession.js
componentDidMount()
let test = this.props.navigation.getParam('test');
test();
}
There are many mistakes within your codes. First of all you are importing the navigation build-in function {createStackNavigator} in all your files, Main.js and Details.js :
import { createStackNavigator, createAppContainer } from
"react-navigation";
That make me think that you didn't know how the stack navigation or navigation in general functions in react native. You should have a file that handles your routes configuration, let call it MyNavigation.js and then define the routes 'Main' and 'details' in MyNavigations,js. It's only inside MyNavigation.js that you can import "createStackNavigator". Then you will define your functions to move between the screens "Main" and "detail". Those functions will be passed as props to the routes when moving between one another. The overall action wihtin MyNavigation.js will look like:
import React from 'react';
import { createStackNavigator } from '#react-navigation/stack';
import { NavigationContainer } from '#react-navigation/native';
import Main from './Main';
import Detail from './Detail';
const Stack = createStackNavigator();
function goToDetailFromMainScreen(){
return(this.props.navigation.navigate('switch2'));
}
function DetailSaves(){
return(//your code here to save details);
}
//Here you pass the functions to Main Component to handele Detail componets
's actions
function switch1(){
return(<Main GoToDetails={() => this.goTodetailFromMainScreen()} paramsForDetailActions={() => this.detailSaves()} />)
}
function switch2(){
return(<Details />)
}
export default function MyNavigation() {
return(
<NavigationContainer>
<Stack.Navigator initialRouteName='switch1'>
<Stack.Screen name='switch1' options={{header:()=>null}} component={Main} />
<Stack.Screen name='switch2' options={{headerTitle:"Detail"}} component={Detail} />
</Stack.Navigator>
</NavigationContainer>
)
}
Now inside Main.js you check the props functions passed to it from MyNavigation.js:
// Main.js
constructor(props){
super(props);
}
goToDetails = () => {
this.props.onPress?.();
}
paramsForDetailActions= () => {
this.props.onPress?.();
}

Cannot read property 'navigate' of undefined in react-navigation

I have used import { StackNavigator } from 'react-navigation'; in my Router.js
import { StackNavigator } from 'react-navigation';
import LoginForm from './components/LoginForm';
import EmployeeList from './components/EmployeeList';
import EmployeeCreate from './components/EmployeeCreate';
const RouterComponent = StackNavigator(
{
LoginForm: {
screen: LoginForm,
navigationOptions: {
title: 'Please Login'
}
},
EmployeeList: {
screen: EmployeeList,
},
EmployeeCreate: {
screen: EmployeeCreate,
navigationOptions: {
title: 'Create Employee'
}
}
},
{
initialRouteName: 'LoginForm',
}
);
export default RouterComponent;
Of course i use it in my App.js
import React from 'react';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import ReduxThunk from 'redux-thunk';
import reducers from './src/reducers';
import Router from './src/Router';
export default class App extends React.Component {
render() {
const store = createStore(reducers, {}, applyMiddleware(ReduxThunk));
return (
<Provider store={store}>
<Router />
</Provider>
);
}
}
And i can use this.props.navigation in my LoginForm.js like this function:
onButtonPress() {
const { email, password, navigation } = this.props;
this.props.loginUser({ email, password, navigation });
}
I pass navigation to my Action file , i can use it to navigate another screen , like this:
const loginUserSuccess = (dispatch, user, navigation) => {
dispatch({
type: LOGIN_USER_SUCCESS,
payload: user
});
//navigation is from LoginForm.js , navigate to EmployeeList is working
navigation.navigate('EmployeeList');
};
Now i try to use this.props.navigation.navigate in my ListItem.js
My ListItem is under EmployeeList.js
Here is my EmployeeList.js
import _ from 'lodash';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { View, Text, Button, FlatList } from 'react-native';
import { employeesFetch } from '../actions';
import ListItem from './ListItem';
class EmployeeList extends Component {
static navigationOptions = ({ navigation }) => ({
title: 'EmployeeList',
headerLeft: null,
headerRight: <Button title="Add" onPress={() => navigation.navigate('EmployeeCreate')} />,
});
componentWillMount() {
this.props.employeesFetch();
}
// Using ListItem over here
renderRow(employee) {
return <ListItem employee={employee} />;
}
render() {
console.log(this.props);
return (
<FlatList
data={this.props.employees}
renderItem={this.renderRow}
keyExtractor={employee => employee.uid}
/>
);
}
}
const mapStateToProps = state => {
const employees = _.map(state.employees, (val, uid) => {
return { ...val, uid };
});
return { employees };
};
export default connect(mapStateToProps, { employeesFetch })(EmployeeList);
Here is my problem use this.props.navigation.navigate in ListItem.js
import React, { Component } from 'react';
import { Text, View, TouchableWithoutFeedback } from 'react-native';
import { CardSection } from './common';
class ListItem extends Component {
onRowPress() {
this.props.navigation.navigate('EmployeeCreate');
}
render() {
const { item } = this.props.employee;
return (
<TouchableWithoutFeedback onPress={this.onRowPress.bind(this)}>
<View>
<CardSection>
<Text style={styles.titleSytle}>
{item.name}
</Text>
</CardSection>
</View>
</TouchableWithoutFeedback>
);
}
}
const styles = {
titleSytle: {
fontSize: 18,
paddingLeft: 15
}
};
export default ListItem;
I can use this.props.navigation in my LoginForm.js , i can't figure it out why i use it in ListItem.js navigate is undefined ?
Any help would be appreciated. Thanks in advance.
in file EmployeeList.js pass navigation as prop to ListItem.
renderRow(employee) {
return <ListItem employee={employee} navigation={this.props.navigation} />;
}
Now you should be able to access navigation using this.props.navigation inside ListItem.js.
Just an observation, never bind methods to context inside the render
function as it is called repeatedly and a new instance will be created
each time. Change your ListItem.js as below.
class ListItem extends Component {
constructor(props) {
super(props);
this.onRowPress = this.onRowPress.bind(this); // here we bind it
}
onRowPress() {
this.props.navigation && this.props.navigation.navigate('EmployeeCreate');
}
render() {
const { item } = this.props.employee;
return (
<TouchableWithoutFeedback onPress={this.onRowPress}>
<View>
<CardSection>
<Text style={styles.titleSytle}>
{item.name}
</Text>
</CardSection>
</View>
</TouchableWithoutFeedback>
);
}
}
Use withNavigation. In your ListItem.js file add import { withNavigation } from ‘react-navigation’; and replace export default ListItem; with export default withNavigation(ListItem);
Here is what I did (using latest react native with ES6):
Refactored the class code from this:
export default class MyComponent extends React.Component {
// content & code
}
To look like this:
import { withNavigation } from 'react-navigation';
class MyComponent extends React.Component {
// content & code
}
export default withNavigation(MyComponent);
According to the docs (withNavigation):
"withNavigation is a higher order component which passes the navigation prop into a wrapped component."

react native Flatlist navigation

I m getting error
TypeError: Cannot read property 'navigation' of undefined. I don't understand how to pass navigation component into each child so when a user presses an item it can navigate to employeeEdit component using React Navigation. i am newbie sorry if this is obvious.
import React, { Component } from 'react';
import { FlatList } from 'react-native';
import { connect } from 'react-redux';
//import { R } from 'ramda';
import _ from 'lodash';
import { employeesFetch } from '../actions';
import { HeaderButton } from './common';
import ListEmployee from './ListEmployee';
class EmployeeList extends Component {
static navigationOptions = ({ navigation }) => ({
headerRight: (
<HeaderButton onPress={() => navigation.navigate('employeeCreate')}>
Add
</HeaderButton>
)
});
componentWillMount() {
this.props.employeesFetch();
}
keyExtractor(item) {
return item.uid;
}
renderItem({ item }) {
return <ListEmployee employee={item} navigation={this.props.navigation} />;
}
render() {
return (
<FlatList
data={this.props.employees}
renderItem={this.renderItem} // Only for test
keyExtractor={this.keyExtractor}
navigation={this.props.navigation}
/>
);
}
}
const mapStateToProps = (state) => {
const employees = _.map(state.employees, (val, uid) => ({ ...val, uid }));
return { employees };
};
export default connect(mapStateToProps, { employeesFetch })(EmployeeList);
Here's the code for ListEmployee
import React, { Component } from 'react';
import {
Text,
StyleSheet,
TouchableWithoutFeedback,
View
} from 'react-native';
import { CardSection } from './common';
class ListEmployee extends Component {
render() {
const { employee } = this.props;
const { navigate } = this.props.navigation;
const { textStyle } = styles;
const { name } = this.props.employee;
return (
<TouchableWithoutFeedback onPress={() => navigate('employeeEdit', { employee })}>
<View>
<CardSection>
<Text style={textStyle}>{name}</Text>
</CardSection>
</View>
</TouchableWithoutFeedback>
);
}
}
/**
second argument in connect does 2 things. 1. dispatches all actions creators
return action objects to the store to be used by reducers; 2. creates props
of action creators to be used by components
**/
export default ListEmployee;
const styles = StyleSheet.create({
textStyle: {
fontSize: 18,
paddingLeft: 15,
}
});
This is one ES6 common pitfall. Don't worry my friend, you only have to learn it once to avoid them all over again.
Long story short, when you declare a method inside React Component, make it arrow function
So, change from this.
renderItem({ item }) {
to this
renderItem = ({ item }) => {
That should solve your problem, for some inconvenient reason, you can only access "this" if you declare your method as an arrow function, but not with normal declaration.
In your case, since renderItem is not an arrow function, "this" is not referred to the react component, therefore "this.props" is likely to be undefined, that is why it gave you this error Cannot read property 'navigation' of undefined since
this.props.navigation = (undefined).navigation
Inside your renderItem method, you can manage what happens when the user presses one an item of your FlatList:
renderItem({ item }) {
<TouchableOpacity onPress={() => { this.props.navigator.push({id: 'employeeEdit'})}} >
<ListEmployee employee={item} navigation={this.props.navigation} />
</TouchableOpacity>
}
Hope it help you!
A navigation sample
here VendorList is the structure rendered
<FlatList
numColumns={6}
data={state.vendoreList}
keyExtractor={(data) => data.id}
renderItem={({ item }) =>
<TouchableOpacity onPress={() => props.navigation.navigate("Home1")} >
<VendorList item={item} />
</TouchableOpacity>
}
/>
in ListEmployee
const {navigation}= this.props.navigation;
this use
<TouchableWithoutFeedback onPress={() => navigation.navigate('employeeEdit', { employee })}>
just need to modification on those two lines, i make text bold what changes you need to do

Why isn't React Native Drawer being triggered using React Native Router Flux + Redux?

I am using the following components to create a React Native + Redux app:
React Native Router Flux
React Native Drawer
I tried following exactly the example provided on how to implement the drawer, yet when navigating to where the drawer should be displayed, using Actions.drawer, I get the error:
But if I try to navigate to the Scene, via Actions.home, inside the drawer Scene, nothing happens but the action REACT_NATIVE_ROUTER_FLUX_RESET is still being called via redux-logger.
Tried following the example exactly but no luck. What could I be doing wrong?
Here is my set up for scene using Redux:
// #flow
import React, { Component } from 'react'
import {
ActionConst,
Actions,
Router,
Scene,
} from 'react-native-router-flux'
import {
Provider,
connect,
} from 'react-redux'
import configureStore from './store/configureStore'
import Login from './components/Login'
import Home from './components/Home'
import NavDrawer from './components/NavDrawer'
const RouterWithRedux = connect()(Router)
const store = configureStore()
export default class App extends Component {
render() {
return (
<Provider store={store}>
<RouterWithRedux>
<Scene key='root'>
<Scene component={Login} initial={true} key='login' title='Login'/>
<Scene key="drawer" component={NavDrawer}>
<Scene component={Home} key='home' title='Home' type='reset' initial={true}/>
</Scene>
</Scene>
</RouterWithRedux>
</Provider>
)
}
}
Then I press a button in Login and it triggers Actions. to navigate to.
The NavDrawer is:
import React, { PropTypes } from 'react'
import Drawer from 'react-native-drawer'
import { Actions, DefaultRenderer } from 'react-native-router-flux'
import NavDrawerPanel from './NavDrawerPanel'
export default class NavDrawer extends Component {
componentDidMount() {
Actions.refresh({key: 'drawer', ref: this.refs.navigation});
}
render() {
const children = state.children;
return (
<Drawer
ref="navigation"
type="displace"
content={<NavDrawerPanel />}
tapToClose
openDrawerOffset={0.2}
panCloseMask={0.2}
negotiatePan
tweenHandler={(ratio) => ({
main: { opacity: Math.max(0.54, 1 - ratio) },
})}
>
<DefaultRenderer
navigationState={children[0]}
onNavigate={this.props.onNavigate}
/>
</Drawer>
);
}
}
And NavDrawerPanel is:
import React from 'react';
import {PropTypes} from "react";
import {
StyleSheet,
Text,
View,
} from "react-native";
import { Actions } from 'react-native-router-flux';
const NavDrawerPanel = (props, context) => {
const drawer = context.drawer;
return (
<View style={styles.container}>
<TouchableHighlight onPress={Actions.home}>
<Text>Home Page</Text>
</TouchableHighlight>
<TouchableHighlight onPress={Actions.login}>
<Text>Login Page</Text>
</TouchableHighlight>
</View>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 30,
backgroundColor: 'black'
},
})
EDIT
Here are what's being imported where the Scene + Redux is set up:
// #flow
import React, { Component } from 'react'
import {
ActionConst,
Actions,
Router,
Scene,
} from 'react-native-router-flux'
import {
Provider,
connect,
} from 'react-redux'
import configureStore from './store/configureStore'
import Login from './components/Login'
import Home from './components/Home'
import NavDrawer from './components/NavDrawer'
EDIT 2 - console.log(this.props)
Doing console.log(this.props) in component Login:
When Actions.home() from component Login:
When Actions.drawer() from component Login:
EDIT 3 - console.log(this.props) inside NavDrawer.js
The NavDrawer never gets rendered so console.log(this.props) doesn't get logged
But with console.log(this.props) inside NavDrawer.js and Actions.home, I get:
And with console.log(this.props) inside NavDrawer.js and Actions.drawer, I get:
I'm not an expert in this but I'm using react-native-router-flux and react-native-drawer in my application without any problems. Some of the differences I see between your code and mine are:
You have two scenes set to initial={true}. This might mess up the Router.
I don't navigate directly to the drawer using Actions.drawer but instead I navigate to the home scene using Actions.home.
If nothing of these works, could you share the render() function of your home component?
Not sure if this is the issue but you don't seem to be importing TouchableHighlight on the NavDrawerPanel component, so:
import {
StyleSheet,
Text,
View,
TouchableHighlight
} from "react-native";
I think you pass in wrong value to navigationState in DefaultRenderer.
It should be
const { navigationState: { children } } = this.props;
In your NavDrawer class
import React, { PropTypes } from 'react'
import Drawer from 'react-native-drawer'
import { Actions, DefaultRenderer } from 'react-native-router-flux'
import NavDrawerPanel from './NavDrawerPanel'
export default class NavDrawer extends Component {
componentDidMount() {
Actions.refresh({key: 'drawer', ref: this.refs.navigation});
}
render() {
//const children = state.children; //wrong
const { navigationState: { children } } = this.props;
return (
<Drawer
ref="navigation"
type="displace"
content={<NavDrawerPanel />}
tapToClose
openDrawerOffset={0.2}
panCloseMask={0.2}
negotiatePan
tweenHandler={(ratio) => ({
main: { opacity: Math.max(0.54, 1 - ratio) },
})}
>
<DefaultRenderer
navigationState={children[0]}
onNavigate={this.props.onNavigate}
/>
</Drawer>
);
}
}
Not sure if this is still something you're working on, but for any others using these libraries, you definitely don't want to use the drawer as a scene. It should wrap you whole router like so:
<Drawer
ref={(ref) => { this.drawer = ref; }}
type="displace"
useInteractionManager
content={
<SideMenuContent
open={this.state.sideMenuOpen}
openDrawer={this.openDrawer}
closeDrawer={this.closeDrawer}
/>
}
tapToClose
openDrawerOffset={0.08}
negotiatePan
onOpenStart={() => { this.setState({ sideMenuOpen: true }); }}
onClose={() => { this.setState({ sideMenuOpen: false }); }}
>
<RouterWithRedux
scenes={this.scenes}
/>
</Drawer>
That's how we have it wired up, and it works well. Then, we just pass these function into our scenes as needed:
openDrawer = () => {
this.drawer.open();
}
closeDrawer = () => {
this.drawer.close();
}