I want side menu in a particular screen in stack navigation.
How can i navigation.push to a screen in stack navigation having a side menu in react native navigation v2. As Navigation.push only takes component object.
Navigation.setRoot({
root: {
stack: {
id: 'App',
children: [
{
component: {
name: 'FormList',
options: {
topBar: {
title: {
text: 'Forms'
}
}
}
}
}
],
}
}
});
I want to push to a screen in CreateForm which would have a sidemenu
const sidemenu = {
sideMenu: {
center: {
component: {
name: 'CreateForm',
options: {
topBar: {
title: {
text: 'Create Form'
},
},
}
},
},
right: {
component: {
name: 'CreateField',
passProps: {
text: ''
},
},
},
}
};
Related
I am using React Native Navigation v2 from WIX in my RN project. For Dashboard(goToDahboard) stack I need to show hamburger icon on the left on on click show side drawer. How can this be implemented?
Since upgrading from v1, side menu options has changed and the docs aren't clear enough.
export const goToDashboard = () =>
Promise.all([
Icon.getImageSource('home', 22, '#272727'),
Icon.getImageSource('th-list', 22, '#272727'),
]).then(sources => {
Navigation.setRoot({
root: {
bottomTabs: {
children: [
{
stack: {
children: [
{
component: {
name: 'Dashboard',
},
},
],
options: {
bottomTab: {
icon: sources[0],
text: 'Dashboard',
},
},
},
},
{
stack: {
children: [
{
component: {
name: 'Settings',
},
},
],
options: {
bottomTab: {
icon: sources[1],
text: 'Settings',
},
},
},
},
],
id: 'bottomTabs',
},
},
});
});
export const goToAuth = () =>
Navigation.setRoot({
root: {
stack: {
id: 'Login',
children: [
{
component: {
name: 'Login',
},
},
],
},
},
});
I'am using like this, thats my code;
Navigation.setRoot({
root:{
sideMenu:{
left:{
component:{
name:'app.Main.SideDrawer'
}
},
center:{
bottomTabs:{
id: 'MainAppBottomTab',
children:[
{
stack:{
children:[
{
component:{
name: 'app.Main.Bottom_1',
options:{
bottomTab:{
text: "Bottom 1",
icon: require('./../../assets/images/Bottom_1.png'),
}
},
}
}
],
options: {
bottomTab: {
text: 'Bottom 1',
},
bottomTabs:{
backgroundColor: ColorTable.orange,
animate:false,
},
topBar:{
title:{
text: 'Bottom 1',
},
leftButtons:[
{
id: 'btn_toggle_drawer',
name: 'BTN_TOGGLE_DRAWER',
icon: require('./../../assets/images/hamburger_icon.png'),
}
],
}
}
}
}
]
}
}
}
}
});
Now we need to use wix's life cycle.
If you want to close it in SideDrawer, you should use the following code;
Navigation.mergeOptions(this.props.componentId, {
sideMenu: {
left: {
visible: false
}
}
});
this.props.componentId equal to app.Main.SideDrawer. Because of we are in app.Main.SideDrawer component.
If you want to open with hamburger icon, Go to whatever page you want to use for bottomTab, in our example I said Bottom_1.
Don't forget to type Navigation.events().bindComponent(this) into the constructor method. This allows you to linking with native.
Only the following command will work;
navigationButtonPressed({buttonId}) {
if (buttonId === "btn_toggle_drawer") {
Navigation.mergeOptions(this.props.componentId, {
sideMenu: {
left: {
visible: true
}
}
});
}
}
The code above works but is problematic. You're going to tell me that I'm going to have to press twice to turn it off =)
The solution is to use redux. Or mobx whichever you prefer.
To solve this problem, I used redux and redux-thunk.
Wix's is life cycle, please explore it: https://wix.github.io/react-native-navigation/#/docs/Usage?id=screen-lifecycle
With redux solution
Real function is;
navigationButtonPressed({buttonId}) {
if (buttonId === "btn_toggle_drawer") {
this.props.toggleDrawer(this.props.isSideDrawerVisible);
Navigation.mergeOptions(this.props.componentId, {
sideMenu: {
left: {
visible: this.props.isSideDrawerVisible
}
}
});
}
}
toggle_drawer action
export const toggleDrawer = (visible) => {
return (dispatch) => {
(visible) ? visible = true : visible = false;
dispatch({
type: TOGGLE_DRAWER,
payload: visible
});
}
};
toggle_drawer reducer
const INITIAL_STATE = {
isSideDrawerVisible: true
};
export default (state = INITIAL_STATE, action) => {
switch (action.type) {
case TOGGLE_DRAWER:
return {...state, isSideDrawerVisible: action.payload};
default:
return state;
}
}
Sample connect function;
import {connect} from "react-redux";
// actions
import {toggleDrawer} from "../../../actions/toggle_drawer";
const mapStateToProps = state => {
return {
isSideDrawerVisible: state.toggleDrawer.isSideDrawerVisible,
}
};
export default connect(mapStateToProps, {toggleDrawer})(Bottom_1_Screen);
Don't forget to connect wix with Redux. https://wix.github.io/react-native-navigation/#/docs/third-party?id=redux
I hope I can help you, I saw it a little late.
Have a nice day..
You can use
Navigation.mergeOptions()
like this to fire and open the drawer:
navigationButtonPressed = ({ buttonId }) => {
const { componentId } = this.props;
if (buttonId === 'sideMenu') {
Navigation.mergeOptions(componentId, {
sideMenu: {
left: {
visible: true,
},
},
});
}
}
i have a created a tab based navigation with WIX and each time i am trying to push a screen from any screen of the tabs it doesn't do anything but , when i try to push from the first tab it works but any other tab i can't push from it
Promise.all(iconTabs).then(sources => { // after the promises end
Navigation.setRoot({
root: {
bottomTabs: {
children: [{
stack: {
children: [{
component: { // 1
name: screenNames['listInvoice'].name,
}
}],
options: {
bottomTab: {
text: screenNames['listInvoice'].title,
icon: sources[0],
selectedIconColor: DEFAULT_COLOR,
},
topBar: getTopBar()
}
}
},
{
component: { // 2
name: screenNames['listReceipt'].name,
options: {
bottomTab: {
text: screenNames['listReceipt'].title,
icon: sources[1],
selectedIconColor: DEFAULT_COLOR,
},
topBar: getTopBar()
}
} ,
},
{
component: { // 2
name: screenNames['listCustomer'].name,
options: {
bottomTab: {
text: screenNames['listCustomer'].title,
icon: sources[2],
selectedIconColor: DEFAULT_COLOR,
},
topBar: getTopBar()
}
} ,
},
{
component: { // 2
name: screenNames['listInvoiceItem'].name,
options: {
bottomTab: {
text: screenNames['listInvoiceItem'].title,
icon: sources[3],
selectedIconColor: DEFAULT_COLOR,
},
topBar: getTopBar()
}
} ,
},
{
component: { // 2
name: screenNames['listSupplier'].name,
options: {
bottomTab: {
text: screenNames['listSupplier'].title,
icon: sources[4],
selectedIconColor: DEFAULT_COLOR,
},
topBar: getTopBar()
}
} ,
},
]
}
}
});
});
-->
Navigation.push(currentScreen, {
component: {
name: screenName,
options: {
topBar: getTopBar(),
bottomTabs: {
visible: false,
drawBehind: true
}
}
}
});
-->
Environment
React Native Navigation version: the latest one
react-native-cli: 2.0.1
react-native: 0.58.4
Platform(s)Android
I had the same issue.
You have to initiate the other tabs a stack layout as well. Like:
bottomTabs: {
children: [
........
{
stack: {
children: [
{
component: { screenNames['listReceipt'].name }
}
]
}
},
{
stack: {
children: [
{
component: { screenNames['listCustomer'].name }
}
]
}
}
]
}
See also here: https://github.com/wix/react-native-navigation/issues/4786#issuecomment-467648825
I have root screen that contains 4 bottoms tabs implemented using react-native-navigation, for one of my bottomtab having sub tabs(topTabs) so now how can I navigate to next screen from the current screen.(note: the next screen is not a registered screen in root)
please anyone help me
here is my root navigation
export const startNavigation = () => {
Navigation.setRoot({
root: {
sideMenu: {
left: {
component: {
name: screenName.DRAWER
}
},
center: {
bottomTabs: {
children: [{
stack: {
children: [{
component: {
name: screenName.Sample1
}
}],
options: {
bottomTab: {
text: 'Sample1',
}
}
}
}, {
stack: {
children: [{
component: {
name: screenName.HOME
}
}],
options: {
bottomTab: {
text: 'Home',
selectedTextColor: 'red'
}
}
}
}],
options: {
bottomTabs: {
currentTabIndex: 1
}
}
}
}
}
}
})
}
from this root, how I will navigate to sub tabs or sunscreens
Have you tried anything? can you post some code?
if you are getting started, here is the official documentation from React Native
https://wix.github.io/react-native-navigation/#/docs/Usage
I'm trying to call Navigate.push from sideMenu but nothing happens.
Navigation.setRoot({
root: {
sideMenu: {
left: {
component: {
name: 'app.SideMenu',
},
children: [
{
stack: {
children: [
{
component: {
name: TERMS_SCREEN.id,
}
},
]
}
}
]
},
center: {
bottomTabs: {
id: 'BottomTabsId',
options: {
topbar: {
visible: true,
}
},
children: [
{
stack: {
id: 'Tabs',
children: [
{
..and I'm trying to push a screen in sideMenu like this
console.log(this.props.componentId);
Navigation.push(this.props.componentId, {
component: {
name: 'app.Terms',
}
})
I am getting the log but nothing happens. I'm positive that I need to do something with my layout but I don't see an example or explanation in docs.
There's something wrong with how you structure the components in the menu. The issue is that you must have a stack to be able to push other screens, and from what it looks - this is not the case for your side menu screen.
This is how you would set a left sideMenu component which is a stack; once you do that, you'll be able to push screens exactly as you did with Navigation.push(this.props.componentId...:
left: {
stack: {
children: [
{
component: {
name: 'app.SideMenu',
}
}
]
}
}
What I was doing wrong is actually because I'm passing the sidemenu componentId when in fact I need to pass the id of the current tab. Something like this.
Navigation.push(`Tab${this.props.activeTabIndex + 1}`,{
component: {
name: Screens.ACCOUNTS,
}
}
)
also sidemenu layout is this
root: {
sideMenu: {
id: 'SideMenu',
left: {
component: {
id: 'SideMenu.left',
name: Screens.SIDEMENU,
}
},
while having children and stack in sidemenu object might be one solution. but you could do this as well. Consider following
Navigation.setRoot({
root: {
sideMenu: {
left: {
id: "AppSideMenu",
component: {
id: "HomeScreenDrawer",
name: "YO.HomeScreen.Drawer",
},
},
center: {
stack: {
id: "AppHomeStack",
children: [
{
component: {
id: "AppHomeScreen",
name: "YO.HomeScreen",
options: {
topBar: {
visible: false,
drawBehind: true,
height: 0,
},
statusBar: {
style: "light",
},
},
},
},
],
},
},
},
},
});
This way when you are going to push just call the ID of your main stack which lies under center{stack:{}} with ID of AppHomeStack
Now anywhere in the app, this will just do the trick
Navigation.push("AppHomeStack", {
component: {
name: "YO.UserScreen",
},
});
I have the next layout:
Navigation.setRoot( {
root: {
sideMenu: {
right: {
component: {
id: 'sideDrawer',
name: DRAWER,
}
},
center: {
bottomTabs: {
id: 'bottomTabs',
children: [
{
stack: {
children: [
{
component: {
id: 'searchTab',
name: SEARCH_TAB,
options: {
bottomTab: {
text: 'Search',
icon: iconsMap[ 'search' ],
testID: 'searchTab',
},
topBar,
}
}
}
]
}
},
{
stack: {
children: [
{
component: {
id: 'secondTab',
name: SECOND_TAB,
options: {
bottomTab: {
text: 'Second Tab',
icon: iconsMap[ 'random' ],
testID: 'secondTab',
},
topBar,
}
}
}
]
}
},
]
}
}
}
}
} )
The drawer is open when a hamburger button in the topBar on any tab is tapped. In the side drawer I have a few menu items. When I tap an item I want to push a new screen to currently active tab ( searchTab or secondTab ). Please note I'm pushing from the drawer component. The challenge is how to know the id of the currently active item to push to or is there any other way to do that?
Ok, figured out. Hopefully this will help someone else also struggling with this. In my drawer component I have a global listener:
constructor( props: Props ) {
super( props )
Navigation.events().registerComponentDidAppearListener( ( { componentId } ) => {
// only spy on tabs we don't need other screens
if (componentId === 'searchScreen' || componentId === 'secondScreen') {
this.setState({
activeComponentId: componentId
})
}
}
Then when I need to open a screen I already have the active component id and can safely push new screen onto it.
openMenuItem( screenName ) {
// close drawer
Navigation.mergeOptions( 'sideDrawer', {
sideMenu: {
right: {
visible: false
}
}
} )
// open menu item
Navigation.push( this.state.activeComponentId, {
component: { name: screenName }
}
}
I used a similar solution by listening to the BottomTabSelected event inside of a react function component.
const [activeTabIndex, setActiveTab] = useState(2 /** My default tab is 2**/ );
useLayoutEffect(() => {
const sub = Navigation.events().registerBottomTabSelectedListener(({ selectedTabIndex, unselectedTabIndex }) => {
setActiveTab(selectedTabIndex);
})
return () => sub.remove();
}, [])
And made each of my bottom stacks have an id that correlated to the tab index.
center: {
bottomTabs: {
children: [{
stack: {
id: "BottomTabs_0",
children: [{
component: {/** Component Info Here **/}
}]
}
},
{
stack: {
id: "BottomTabs_1",
children: [{
component: {/** Component Info Here **/}
}]
}
},
{
stack: {
id: "BottomTabs_2",
children: [{
component: {/** Component Info Here **/}
}]
}
}]
}
}