Closed musicode closed 7 years ago
@musicode This functionality is indeed missing, we'll add it soon.
Took a stab at this because I needed to know if a drawer was toggled for hiding the status bar. Still pretty new to this library and my Objective-C sucks, so bear with me.
I decided that adding a listener to the NativeAppEventEmitter(only tested this on iOS) was probably my best route to make sure that I didn't introduce any breaking changes. So here we go.
After my store has been initialized I add an event listener:
NativeAppEventEmitter.addListener('ReactNativeNavigationEvent', (event) => {
console.log(event);
// We get access to everything that is passed when performing something like
// this.props.navigator.push({...}); The only addition is that there is a type that is added
// in the form of NavigationEvent_{performAction} eg: NavigationEvent_push.
});
With the code above if you're using Redux you can dispatch an action to a reducer that is set up to handle those types of actions and take what you want from the event object such as the component string and update your state.
In the ReactNativeControllers iOS project I created a helper called RCCNavigationEventNotifier with a static method sendNavigationEvent.
+ (void)sendNavigationEvent:(NSString*)actionType actionParams:(NSDictionary*)actionParams
{
[[[RCCManager sharedInstance] getBridge].eventDispatcher sendAppEventWithName:@"ReactNativeNavigationEvent" body:@
{
@"type": [NSString stringWithFormat:@"NavigationEvent_%@", actionType],
@"params": actionParams
}];
}
Pretty much just copied what the buttons use to send events to listeners. After importing the header file to RCCNavigationController.m I added the following to the performAction:
// Array of nav actions that can trigger a navigation event.
NSArray *navEventActions = @[@"push", @"pop", @"popToRoot", @"resetTo"];
if ([navEventActions containsObject:performAction]) {
[RCCNavigationEventNotifier sendNavigationEvent:performAction actionParams:actionParams];
}
Pretty quick and dirty right now, but it works pretty well for my needs to be able to update my state with nav events. I know that you said that you'll add this soon, if this is the right direction I can certainly clean it up and make a pull request or trash it. It's all local right now so if you want to take a closer look I can make a fork as well.
how cant I get current screen in v2.0?
I didn't find the api. the feeling of v2.0 is the same as v1.0.
@musicode well, 2.0.0 isn't out yet. You are using the experimental pre-release.
The current state of the framework is that we try to create parity between the platforms, unify both controllers and navigation, and upgrade to RN31. After that we have a bunch of refactoring and redesign of the architecture to do. One of the requested features is indeed accessing a specific screen somehow. This will be addressed.
+1 for this. Not sure if this would be returned by getCurrentScreen
but I am also in need of a method to get the current title and navigator buttons. I want to call navigator.setTitle()
but first save the previous title so I can roll back to it later programmatically if need be. Or maybe there is another way to do this..?
When to support this feature?
hi, have any new messages? I have wait it for 4 months, it is so long...
@musicode I feel your pain, and truly appreciate the patience. Deciding on the new architecture is not easy but it is my current and complete focus. I think we will have something ready in the upcoming month
@DanielZlotin thanks, I hope RNN could release 2.0 in the upcoming month.
many many thanks to you.
A month has passed..
Hi guys, sorry to pester, just wondering if there are any updates on this, even suggestions no how it might look?
Thank you for your patience. We are working hard on the v2 api that will solve this, among other things.
hi, any updates on this?
@musicode Screen lifecycle events were added in .233 https://github.com/wix/react-native-navigation/wiki/Screen-API#screen-visibility
thanks!
I have a question, there are many images in the demo gif of README, I want to know which component is used for display the fullscreen image when user press the thumbnail.
the component should support zoom by double tap, moving with finger, and the most important is, we hope as smooth as possible.
@guyca What do you think of react-navigation, I found it yesterday, but it's more difficult than RNN.
I have read its document for one day, but I still did't know how to get started...
It's recommand by react-native, so it double me.
I want to use RNN, but I don't know whether it's really ready for production, I don't know ios and android, i'm so helpless when some bugs is arised.
for more, i need some native components like image and rich text editor, i hope RNN will not conflict with the other native component.
that is all my doubt, I hope you could give me a answer.
thank you!
There's still no way to getCurrentScreen, right?
Just to be clear,
Is 2.0 usable?
@musicode I was just looking at that because of so many problems here. Did you ever investigate?
@musicode @jameskhamil try #1118 ? I actually used react-navigation first, and then switched to this package. I find this has better performance, but RN is JS based so debugging is easier. My biggest issue with RN was that at the time, there was no way to disable swipe gestures (to hide side drawer).
That still relevant, how do I get the current screen data?
Something like:
Navigation.getCurrentScreen()
I'm trying to find it out, but docs are not helping.
Any solution? I need to know what the current screen is visible.
@rodribech20 As a workaround I'm traking the componentDidAppear event and storing the last component in a variable that is in a singleton in my app, it is working fine.
Thanks @emilioheinz it is a feasible solution. The thing is I have many screens on my App.
@rodribech20 I know... I have too, the thing is that you can use the global event to track it. In my app I have around 30 screens and it is working fine.
My registerComponentDidAppearListener
function that is in the first file loaded in the application:
Navigation.events().registerComponentDidAppearListener(data => {
const { componentName } = data
const { COMPONENT_DID_APPEAR_BLACK_LIST } = NAVIGATION_CONSTANTS
if(!COMPONENT_DID_APPEAR_BLACK_LIST.includes(componentName)) {
NavigationService.setCurrentScreenData(data)
}
})
I'm using a black list to do not save components that are registered and are not a screen from where I can push another screen, components like topBar custom buttons.
NavigationService
is a singleton service where I wrap all the Navigation functions and store the last pushed screen data.
class _NavigationService {
constructor() {
this.currentScreen = {}
}
setCurrentScreenData(data = {}) {
this.currentScreen = data
}
// Other functions like push, mergeOptions, pop etc
}
So in any place of my application I can access NavigationService.currentScreen
and I have the currentScreen data.
I hope it helped you 😉
@emilioheinz Great! I'm going to try it if it works for me. Thanks!!!
After trying let us know if it worked...
@emilioheinz Yes it is working! It is a great workaround . Thank you very much!
@rodribech20 I know... I have too, the thing is that you can use the global event to track it. In my app I have around 30 screens and it is working fine.
My
registerComponentDidAppearListener
function that is in the first file loaded in the application:Navigation.events().registerComponentDidAppearListener(data => { const { componentName } = data const { COMPONENT_DID_APPEAR_BLACK_LIST } = NAVIGATION_CONSTANTS if(!COMPONENT_DID_APPEAR_BLACK_LIST.includes(componentName)) { NavigationService.setCurrentScreenData(data) } })
I'm using a black list to do not save components that are registered and are not a screen from where I can push another screen, components like topBar custom buttons.
NavigationService
is a singleton service where I wrap all the Navigation functions and store the last pushed screen data.class _NavigationService { constructor() { this.currentScreen = {} } setCurrentScreenData(data = {}) { this.currentScreen = data } // Other functions like push, mergeOptions, pop etc }
So in any place of my application I can access
NavigationService.currentScreen
and I have the currentScreen data.I hope it helped you 😉
It worked for me as well, but sometimes it makes navigator work way too slow, because of checking after each screen changing. So I created a method inside my navigator controller, that I imported to my screens, and passed screen name as a props.
activeTabController(componentId) {
const { activeBottomTab } = this.state;
activeBottomTab !== componentId && this.setState({
activeBottomTab: componentId
})
}
I know that this is not a very beautiful solution, but it works for me really faster than:
Navigation.events().registerComponentDidAppearListener()
Anyway, thank you for helping.
I wrote a hook that seems to be working for this.
import { useEffect, useState } from 'react';
import { Navigation } from 'react-native-navigation';
/**
* Gets the current navigation screen
*/
export function useGetCurrentScreen(): string {
const [currentScreen, setCurrentScreen] = useState('');
useEffect(() => {
let isMounted = true; // note this flag denote mount status
Navigation.events().registerComponentDidAppearListener(({ componentId }): void => {
if (isMounted) setCurrentScreen(componentId);
});
return (): void => {
isMounted = false;
}; // use effect cleanup to set flag false, if unmounted
});
return currentScreen;
}
Great workarounds, but is there any chance we'll see something like Navigation.getCurrentScreen()?
@JamesLarson Yes. Once RNN switches to a sync API with JSI we will probably expose this method. But as long as our API is async, we're refraining from introducing this API as it will result in poor performance and design on your end.
The hook proposed by @samuelseaton is exactly what I was looking for. It will be nice to see those hooks on react-native-navigation-hooks, don't you think it so @underscopeio?
import { useContext } from 'react'
import { NavigationContext } from 'react-native-navigation-hooks'
const useNavigationComponentId = () => {
const { componentId } = useContext(NavigationContext)
return componentId
}
export default useNavigationComponentId
import { useEffect, useState } from 'react'
import { Navigation } from 'react-native-navigation'
import useNavigationComponentId from './useNavigationComponentId'
const useNavigationCurrentComponentId = () => {
const componentId = useNavigationComponentId()
const [currentComponentId, setCurrentComponentId] = useState(componentId)
useEffect(() => {
const subscription = Navigation.events().registerComponentDidAppearListener(event => {
setCurrentComponentId(event.componentId)
})
return () => {
subscription.remove()
}
}, [])
return currentComponentId
}
export default useNavigationCurrentComponentId
i call navigator.push() to push a screen, then i press back button.
if i want to get the current screen, i thick there are two ways:
push
andpop
i think the first way is better, but now, how can i do it ?