How to access data from navigateOptions of Navigation Drawer - reactjs

I have a trouble with getting data from props in my Sidebar, I coded it like this using Navigation Drawer.
How can I access for example that text ("xd") from navigationOptions or how can i pass an object there
and read it correctly?
contentComponent: props => <SideBar {...props } />, navigationOptions: {
icon: 'xd'
},
Rest of the code
export default Sidebar = props => (
{..Something not important in that question}
<DrawerNavigatorItems {...props} style={{
}}/>
</View>
</ScrollView>
);

I'm not sure what exactly your use case is, but it might be easier to just pass icon directly to the SideBar component as a prop:
contentComponent: (props) => <SideBar {...props} icon="xd" />
Then you can retrieve the icon value passed to your SideBar component like this:
export default Sidebar = (props) => (
<ScrollView>
<Text>{props.icon}</Text>
</ScrollView>
);
I've used the Text component to give an example, but replace the Text component with the views you want.

Related

How to call drawer navigator inside function in react native

I am new to React-native. So I don't know much about navigation. When I click my image I need to open my drawer side menu.
I called my drawer inside the function.
const Drawer = createDrawerNavigator();
function TopBar(props) {
function sideMenuHandler() {
return (
<NavigationContainer>
<Drawer.Navigator>
<Drawer.Screen name="SideBar" component={SideBar} />
</Drawer.Navigator>
</NavigationContainer>
);
}
return (
<>
<View>
<TouchableWithoutFeedback onPress={sideMenuHandler}>
<Image source={require('../assets/profile.jpg')} onPress{sideMenuHandler}/>
</TouchableWithoutFeedback>
</View>
</View>
</>
);
}
First you have to describe your Drawer at the Root of your application as desribed in the docs.
Answering your question opening, toggling or closing a Drawer pane programmically you can use DrawerActions or the shortcut described below.
Import useNavigation to access navigation props.
import { useNavigation } from '#react-navigation/core';
Apply Actions by dispatching them:
const navigation = useNavigation();
const handlePress = () => {
navigation.toggleDrawer();
}

Issue with rendering a component as a prop

I have a layout component which acts as follows:
const Layout = ({ children, sider }) => (
<div>
<div>{sider}</div>
{children}
</div>
)
But I can't implement it as expected. I'm hoping to get it implemented as follows:
<Layout sider={Sider}>
Body Content Here
</Layout>
Where Sider is another React component.
However when I do this, my Sider component doesn't render.
I can only get it to work like this:
<Layout sider={<Sider />}>
Body Content Here
</Layout>
How can I update my Layout component so that I can implement sider={Sider} instead of sider={<Sider />}?
Your 2nd approach is correct however if you still want to do that way, do like this
const Layout = ({ children, sider: Sider }) => (
<div>
<div>
<Sider />
</div>
{children}
</div>
)
Another method to handle this is to use React.createElement()
Example:
const Layout = ({ children, sider }) => (
<div>
<div>{React.createElement(sider)}</div>
{children}
</div>
)

Transition custom header component React Navigation

I am creating a React Native app that's supposed to have a custom header for basically all screens, so I've made a Navbar component that I have set as a default header which works fine. Although when I navigate between screens in the app, the header is not transitioning as it is supposed to be. With a standard header, the old one fades out and the new one in when you navigate to another route in the stack, but mine just replaces itself automatically.
I believe the problem might revolve around that all screens have the "same" Navbar component, that is there is not a new one created for each screen, so when I navigate it just updates the props of the navbar and re-renders it.
Here is the navigator setup
App.js
...
const stackNavigator = createStackNavigator(
{
...
}, {
initialRouteName: "Home",
defaultNavigationOptions: ({ navigation }) => ({
header: (headerProps) => {
return <Navbar navigation={navigation} {...headerProps.scene.descriptor.options} /> //Will pass navigationOptions as props
},
animationEnabled: true
}),
navigationOptions: {
animationEnabled: true,
},
headerTransitionPreset: 'fade-in-place',
transitionConfig: () => {
return {
transitionSpec: {
duration: 2000, //Easier to see the navigation animation
}
}
}
);
The Navbar component is a regular React.Component, along with all other screen components if that makes any difference
Are there some kind of props I should take care of? I have search all over the web, especially on the React Navigation docs and API reference but have found no info.
Here are some examples of how it looks with my custom navbar and how it looks with the default header. Note that the default fades during the whole transition while my custom just switches view in an instance. The only change I made was comment out the header: ... part
Custom
https://imgur.com/PXvm7gA
Default
https://imgur.com/yk3jyr9
If I understood it correctly your header is not navigating with screen? If that is the case use headerMode='screen' According to react-navigation 5.*
<NavigationContainer>
<Stack.Navigator initialRouteName="List" headerMode='screen'>
<Stack.Screen name="Article"
component= { Article }/>
<Stack.Screen name="List"
component= { List }/>
</Stack.Navigator>
</NavigationContainer>
header mode set to screen navigate the header with screen which is common in android where as if you set it to float header will not navigate but changes its content which is common in ios. set it to none if you dont want header.
I'm on react-navigation#5.1.3 and the following works for me (taken from my code):
<Stack.Navigator>
<Stack.Screen
name={"route1"}
component={Route1View}
options={{title: "route 1 title"}}
/>
<Stack.Screen
name={"route2}
component={Route2View}
options={({navigation, route}) =>({
title: "route 2 title",
header: (props) => <CustomHeader {...props} />
})}
/>
</Stack.Navigator>
If you start with route 1, the default header is shown. When you push route 2, the custom header will fade in. When you leave, the default will show once again.
You can specify any component for left and right in the header in the screen configuration, you can have something like this:
createStackNavigator({
home: {
screen: (props) => (
<View style={{flex: 1}}>
</View>
),
navigationOptions: () => ({
title: `Title`,
headerRight: (
<React.Fragment>
<Button title={'First'} />
<Button title={'Second'} />
</React.Fragment>
)
})
},
});

How to add different child components to component

I'm new to react. I'm trying to create the following structure for a component in react:
<Sidebar>
<Box>
<Title/>
<Item/>
<Item/>
</Box>
<Box>
<Title/>
<Switch/>
</Box>
</Sidebar>
I can include the Title component in the Box component and pass each title value through props. How do I include the Item component in just the first Box component and not the second?
Is the best way to pass the Item and Switch components into the Box components as props?
There are quite a few ways to do what you're asking and really it really depends on where you are going with your program.
Multiple Types of Box components (with different names)
Wrap all of you sub-components in a div, and pass that div to your Box's 'children' prop. (Slightly changes your hierarchy).
Example
<Box children={<div><Title/><Item/><Item/></div>}/>
<Box children={<div><Title/><Item/></div>}/>
Hierarchy
<Sidebar>
<Box>
<div>
<Title/>
<Item/>
<Item/>
</div>
</Box>
<Box>
<div>
<Title/>
<Switch/>
</div>
</Box>
</Sidebar>
More fancy, build your sub-components from an array or other JS object that you pass as a prop and have a function inside 'Box' that reads that array and builds your sub components.
Leverage the special children prop in order to render arbitrary children:
children is a default prop passed implicitly to every component
this children prop is automatically populated with any elements contained within the parent component
instead of using props.children you can destructure props and use ({ children(, ...otherProps) }) instead
In action:
Box.js
const Box = ({ children }) => (
<div className='box'>
{children}
</div>
)
Sidebar.js
const Sidebar = ({ children }) => (
<div className='sidebar'>
{children}
</div>
)
App.js
import React from 'react'
import Sidebar from './path/to/Sidebar'
import Box from './path/to/Box'
class App extends React.Component {
constructor() {
super()
// state or whatever
}
render() {
return (
<Sidebar>
<Box>
{/*
Anything you put in here (other components
included) will be automatically rendered
*/}
</Box>
<Box>
{/* Same here */}
</Box>
</Sidebar>
)
}
}

Differences passing Redux state through passProps with Navigator or binding state within Container

Testing React Native with Redux, and react-redux, I've found that the content of the state tree of Redux is not reflected in the display if the state is not passed through a Container.
To test this i use
react-native 0.19.0
react-redux 4.1.2
redux 3.1.7
as #alinzin explain in https://github.com/alinz/example-react-native-redux with all the tricks to setup this project. Are out there any other good solution?
The next example show a simple string as state in Redux store, and a simple action for enlarge the string.
Here is the reduce and the data as a single string in the state.
//Reducer
const reducer = (state = { data: '[][][]' }, action = {}) => {
switch (action.type) {
case ENLARGE:
return Object.assign({}, state, {
data: state.data+'[]'
})
default:
return state
}
}
The registred App is like this, nothing new. The initial route launches a Container for App1Component. This is the way for good binding state and Components (I belive)
export default class App extends Component {
render () {
return (
<Provider store={store}>
<Navigator style={{flex: 1}}
initialRoute={{
component: Container,
}}
renderScene={ (route, navigator) => {
const Component = route.component;
return (
<View style={{flex: 1, marginTop:40}}>
<Component navigator={navigator} route={route} {...route.passProps} />
</View>
);
}}
/>
</Provider>
)
}
}
The main content for both component App1Component and App2Componenet, is a simple component and just display the string, and show a 'button' to dispatch the enlarge action.
class MainContent extends Component{
render() {
return (
<View>
<Text>{this.props.data}-{this.props.data.length}</Text>
<TouchableOpacity onPress={()=>{this.props.enlarge()}} >
<Text>Click to Enlarge me!</Text>
</TouchableOpacity>
<Text> </Text>
</View>
)
}
}
There are no differences between components App1 and App2.
Just App1Component is invoked through a Container (and bind state and actions), and App2Component invoked (from App1Component) by pushing with Navigator all the same props (the same in App1Component)
Here is App1Component with a button to push next scene to App2Component and pass the same props, before binded through Container.
class App1Component extends Component {
render() {
return (
<View>
<MainContent {...this.props}/>
<TouchableOpacity onPress={()=>{
this.props.navigator.push({
name: 'App2',
component: App2Component,
passProps: {...this.props}
})
}}>
<Text>Click to Forward to App2Component {'\n'}passing props through Navigator passProps</Text>
</TouchableOpacity>
</View>
)
}
}
If you press 'enlarge' here the string is enlarged, and you can see the action reflected on the screen. Also you can see in chrome the trace for redux logger.
Here the wrapper container for App1Component
const Container = connect(
(state) => ({
data: state.data
}),
(dispatch) => ({
enlarge: () => dispatch(enlarge())
})
)(App1Component)
And Here Component 2, with back button.
If you press 'enlarge' here the string is enlarged, sure you can see the trace on chrome, but ... the action is not reflected on the screen.
class App2Component extends Component {
render() {
return (
<View>
<MainContent {...this.props}/>
<TouchableOpacity onPress={()=>{this.props.navigator.pop()}} >
<Text>Back to App1Component{'\n'}to see the change!</Text>
</TouchableOpacity>
</View>
)
}
}
After pressing Back, you can see the string modified on screen for App1Component.
As you can see I misunderstood something fundamental, but not what is.
Have i to decorate all the mains components (Pages/Scenes) with a container?
Why is wrong to pass props (previously binded by container) through passPros in Navigator? Actions are dispatched correctly, but does not reflect on the screen.
Any help is welcome.
Thanks
It looks like passProps does not propagate updates correctly. I’m not a React Native expert so I can’t confirm it, but I would definitely recommend you to use connect() for subscribing components to Redux store rather than passing props from the top.

Resources