How to pass navigator reference to nested child components? - react-native

I want to make navigation drawer list item clickable, in that scenario i want navigator object to navigate another scene. How can i pass navigator reference there from main component to child component? My child components of Main components are ListView and ListItems. Any suggestion will be helpful.

You are able to pass it down just like any other prop. I'm assuming you're passing navigator down to the routed component...
<Navigator
ref='Navigator'
renderScene={(route, navigator) => {
let RoutedComponent = route.component
return (
<RoutedComponent navigator={navigator} {...route.props}/>
)
}}
/>
If so, in the RoutedComponent just pass the navigator down to it's child components through props.
<MyChildComponent navigator={this.props.navigator}/>

Related

Why useNavigation hook doesn't work in custom side bar?

If I create custom drawer:
<DrawerStack.Navigator
drawerContent={props => <SideMenu {...props} />}>
It requires to pass props in order to get navigation object inside it.
And if I have following:
<ClientsStack.Navigator>
<ClientsStack.Screen name="Clients" component={ClientsScreen} />
<ClientsStack.Screen
name="ClientDetails"
component={ClientDetailsScreen}
/>
</ClientsStack.Navigator>
And inside ClientsScreen I have FlatList which has:
renderItem={({ item }) => <ClientCard id={item.id} />}
inside ClientCard component which is not screen it's just dummy component
I can use useNavigation hook there.
Why it can be used there but not in custom drawer component?
You can't use useNavigation inside your drawerContent cause the hook is only available from your screens and their childs.
At the origin the only way to get navigation was to pass it from your screen to their childs. But since the useContext hook exist, the library provides a useNavigation to easily get the navigation in deep nested components. (and simplify the code a lot)
A drawer custom component is not a screen or wrapped into a screen. So there is just no reason to get the navigation from it with useNavigation. And I easily guess there is no usecase where we have deep nested components inside it cause it is usually just a menu.

React Navigation passing function as parameter

so i have lot of screen that have similar function eg:
ForgotPasswordCaptcha
ForgotUserIDCaptcha
RegisterCaptcha
these screens have same layout and functionality except they have different "Next" Button function in ForgotPassword users will be redirected into loginscreen, in ForgotUserID the user will be redirected into page that shows his userID. and in Register it will redirect user to Succes Page.
.
so the function that i create in navigator is handleOkay, and when i press the button in SomeReusableScreen it gives me this warning
Non-serializable values were found in the navigation state. Check:
forgotUserIDStackScreen > FUinputCASAScreen > params.handleOkay (Function)
This can break usage such as persisting and restoring state. This might happen if you passed non-serializable values such as function, class instances etc. in params.
what i want to achieve is i to pass function as parameter in Stack navigator so the screen will just invoke that function to redirect/doing something with redux,
i dont know i should ignore this warning since in other screens it will handle redux sagas, set asyncstorage
so i have found the way to do what i wanted.
instead of passing the screen as component in Stack.Screen i pass it as child like this
<Stack.Screen
initialParams={{progress: 0.2}}
name={routes.nameofthisroute}
options={({navigation, route}) => ({
headerTitle: props => {
let currentProps = {navigation, route};
return <NavigationHeaderTwo {...currentProps} />;
},
...otherStyle,
})}>
{props => (
<PickMethodScreen handlePickMethod={handlePickMethod} {...props} />
)}
</Stack.Screen>
and i props some function and state from Stack Navigator and its written in this docs here
we can also create react context so component can consume it without having lot of props
I implemented a very simple example to clear the concept. You can pass function as a prop and can dispatch up to the parent component using the same props key. This way you can utilize reusable component.
//consider this your generic Component
function IButton(props){
//receive the method as props
//dispatch the method back to the parent
return (
<button onClick={()=>props.handleClick('hello')}>click me </button>
)
}
const App=()=>{
function handleOnClick(text){
alert(text);
}
return(
<div>
{/*pass the function as Prop*/}
<IButton handleClick={handleOnClick}/>
</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>

How to Create Drawer menu without Navigation?

I am looking to create a drawer, similar to a drawer navigator, but without the routes/navigation requirement.
I plan on placing some other components there that update a query. Any recommendations? Specifically the drawer would be used to display picklists, sliders, and date range components that would update the state and variables used in updating markers rendered on a map shown on the home page.
With Redux
You can use the contentComponent of the createDrawerNavigator to create your own custom drawer and bind it to redux-store.
By dispatching the actions with relevant queries you can update the variables as they are passed from the store to your Component.
Without Redux
You can either create a CustomDrawer component with similar animation and render it in your Component or use this react-native-drawer.
import Drawer from 'react-native-drawer'
class Application extends Component {
closeControlPanel = () => {
this._drawer.close()
};
openControlPanel = () => {
this._drawer.open()
};
render () {
return (
<Drawer
ref={(ref) => this._drawer = ref}
content={<DrawerContentComponent {...// Your Updater props}/>}
>
<Component />
</Drawer>
)
}
})

React this.props.navigation.openDrawer() in child component?

I have an openDrawer method via React Navigation 2 working great in my View. However, when I create a child component and place my openDrawer button in it, I can no longer access this.props.navigation. How do I pass that down into the child component? I looked at state but that doesn't seem to be the correct way to address this? I am new to React/Native. Here is my button inside the main view and it works fine this way.
<View style={styles.menuBar}>
<TouchableOpacity style={styles.menuButton}
onPress={() => this.props.navigation.openDrawer()}>
<Text>☰</Text>
</TouchableOpacity>
// Other Stuff inside menuBar.
</View>
This menu button has a few other items as well and I am wanting to group together in a class component as a child that I can just import into various screens.
import { topMenuBar } from '../components/menuBar';
<topMenuBar />
However, the menu button no longer works now. I know it's because this.props is now referring to class topMenuBar and not the original class which is part of the nav structure. But I don't know the proper procedure for this step, whether it's using state or calling NavigationActions from react-navigation in the child method somehow.
Thanks for the help!
Every component opened using react-navigation has "this.props.navigation".
If you need it in child components you should pass to them as a prop:
export default class Home extends Component{
render(){
<View>
<OtherComponent navigation = {this.props.navigation}/>
</View>
}
}
Note: if you want a better help you should always provide code creating a fiddle and organize better your answers..

TabBarIOS - Is there a viewDidAppear or viewWillAppear equivalent?

Specifically for writing a callback from within a child component of a TabBarIOS.item that is triggered when a Tab is selected. (TabBarIOS in React Native)
There is no callbacks for ViewDidAppear and ViewWillAppear for tabs. You can pass a prop like isTabAcitve in TabIOSItem child component. And implement your child component depending upon isTabActive value. Your code TabBarIOSItem can look something like this:
<TabBarIOS.Item
title=""
selected={this.isTabActive("my-account-tab")}
icon={require("./img/user-tab.png")}
onPress={() => {
this.setState({activeTab:"my-account-tab"});
}}>
<MyAccountTabisTabActive={this.isTabActive("my-account-tab")} />
</TabBarIOS.Item>
isTabActive can be a method in your component containing TabIOS:
isTabActive(tabName)
{
return this.state.activeTab == tabName;
}
Also TabBarIOS don't render all tabs at once, A TabBarIOS child component is initialised and mounted for first time only when that tab is pressed for first time. So componentWillMount and componentDidMount can also be used as alternative of viewDidAppear and viewWillAppear.