set header for drawer navigation - react-navigation

I tried to set header in react navigation v5 by setting options without any change
<Drawer.Navigator
initialRouteName='...'
>
<Drawer.Screen
name='...'
component={Component}
options={{ title: 'My home' }}
/>
</Drawer.Navigator>
is there a way I could have my react navigation header in drawer?

Update: The latest version of drawer navigator now has a header (can be shown with headerShown: true)
Drawer Navigator doesn't provide a header.
If you want to show headers in drawer screens, you have 2 options:
Provide your own header component. You can use header from libraries such as react-native-paper
Nest a Stack Navigator in each drawer screen where you want to show a header.

I was looking for the solution, however did not find any nice way to wrap up every component automatically with custom header. So I ended up creating HOC component and wrapping each component for every screen.
import React, {Fragment} from 'react';
const NavHeader = props => {
// ... NavHeader code goes here
};
export const withHeader = Component => {
return props => {
return (
<Fragment>
<NavHeader {...props} />
<Component {...props} />
</Fragment>
);
};
};
Then in your Drawer you do:
<Drawer.Navigator>
<Drawer.Screen
name={ROUTES.DASHBOARD}
component={withHeader(DashboardContainer)} // <--- Wrap it around component here.
/>
</Drawer.Navigator>

This is a simple example with react navigation 5:
function Root() {
return (
<Stack.Navigator>
<Stack.Screen name="Profile" component={Profile} />
<Stack.Screen name="Settings" component={Settings} />
</Stack.Navigator>
);
}
function App() {
return (
<NavigationContainer>
<Drawer.Navigator>
<Drawer.Screen name="Home" component={Home} />
<Drawer.Screen name="Root" component={Root} />
</Drawer.Navigator>
</NavigationContainer>
);
}
You can find about the navigation to a screen in a nested navigator in docs and you can try this example on Snack

Related

React-native Why Menu is not rendering

i have a menu for each item of a flatlist, however when ever i press on the button to show the menu nothing happens when i log the visible state of the menu i see that it is being set to true but it is not rendering.
this is a component to render each item with a menu
const RenderItem =(props)=>{
return(
<TouchableOpacity onPress={()=>{}}>
<View style={styles.flatitem}>
<Icon style={styles.pdf} name="file-pdf-o" color="#666"/>
<Text style={styles.itemtext}>{props.title}</Text>
<Menu
visible={visible}
{...console.log(visible)}
anchor={<Button onPress={openMenu} >
show
</Button>}
onDismiss={closeMenu} >
<Menu.Item icon="pencil-box-outline" onPress={() =>{}} title="Rename" />
<Menu.Item icon="label-outline" onPress={() => {}} title="Label" />
<Menu.Item icon="delete-outline" onPress={() => {}} title="Delete" />
</Menu>
</View>
</TouchableOpacity> )}
this is the flatlist:
<FlatList style={styles.flatstyle}
keyExtractor={(item)=>item['id']}
data={DATA}
renderItem={({item})=>(<RenderItem title={item.title }/>)}
/>
and these are the open and close functions
const [visible,setVisible]=useState(false)
const openMenu = () => {
setVisible(true)
}
const closeMenu = () => setVisible(false);
If i am right, it is actually not a problem. FlatList is a pure component and will only re-render if the data prop changes i.e, the data passed to the flatlist changes.
As visible is not in data, so it doesnot re-render.
To make it re-render and show the menu, you need to use extraData prop of the flatlist, which will take some other data. If that other data changes, that will also cause a re-render and that other data in your case is the visible variable.
More details here

In nested stack navigation in react-navigation. it does not to scroll up

I have a problem.
I had coded react-native and react-navigation.
In 'HOME' screen, I had scrolled down, and When I had pressed the icon 'HOME',
There are no any changes to scroll.
Certainly, I have used 'ref - useScrollToTop method', But I cannot go to screen up
<Tab.Navigator>
<Tab.screen name='home' component={HomeNavigation} options={{ <Image ...(blah blah) /> }} />
</Tab.Navigator>
----
<HomeNavigation.Navigator initialRouteName="Main" name="Main" component={HomeTopTabNavigation}>
<HomeNavigation.Screen name="Main" component={HomeTopTabNavigation} />
<HomeNavigation.Navigator />
----
<HomeTopTabNavigation.Navigator initialRouteName='NEW'>
<HomeTopTabNavigation.Screen name="NEW" component={Home} />
<HomeTopTabNavigation.Screen name="HOT" component={HOT} />
</HomeTopTabNavigation.Navigator>
----
const Home = ({ navigation }) => {
const ref = React.useRef(null); *******. This ref does not work !
useScrollToTop(ref); *******. This ref does not work !
...
return (
...
<FlatList
ref ={ref} *******. This ref does not work !
...
/>
)
}
more specific navigation name in this picture. please see this.

gatsby-sharp images loaded via graphql in react-carousel not activated

I have created a react-bootstrap carousel with some images I load via graphql and gatsby-image-sharp (the source images are in directus).
I see the images are created in the code, but they never get assigned the "active" class. When I put the images outside of the carousel, they are shown correctly one below the other, so the retrieval seems to work fine.
If I manually add an item before and/or after the graphql images, those slides get shown correctly.
I also see that in case I put a slide before and after the graphql ones, the first "normal" slide gets shown and when the transaction is started, I get a delay corresponding to the number of generated slides before the next statically created slide is shown again.
When inspecting the site with the react development tools, I see the working slides have a transaction key of ".0" and ".2", while the non-working slides between them have transaction keys of ".1:0:0", ".1:0:1", etc...:
React devtools tree
The code I use to generate this is included below:
import React from "react"
import { Row, Col, Container, Carousel } from "react-bootstrap"
import { graphql } from "gatsby"
import Layout from "../components/layout"
import SEO from "../components/seo"
import Img from "gatsby-image"
const IndexPage = ({ data }) => (
<Layout pageInfo={{ pageName: `index` }}>
<SEO title="Home" keywords={[`gatsby`, `react`, `bootstrap`]} />
<Container className="text-center">
<Row>
<Col>
<Carousel>
<Carousel.Item>
<div className="d-block w-100 gatsby-image-wrapper">
<h1>test</h1>
</div>
</Carousel.Item>
{data.allDirectusSlideshow.edges.map((slideShow) => {
return slideShow.node.images.map((image) => {
const sharp = data.allImageSharp.edges.find((imageSharp) => (
imageSharp.node.fluid.originalName === image.filename_disk))
return <>
<Carousel.Item key={sharp.node.id}>
<h1>Image</h1>
<Img fluid={sharp.node.fluid} className="d-block w-100" />
</Carousel.Item>
</>
})
})}
<Carousel.Item>
<h1>Test 2</h1>
</Carousel.Item>
</Carousel>
</Col>
</Row>
</Container>
</Layout>
)
export const query = graphql`
query {
allDirectusSlideshow(filter: {title: {eq: "Voorpagina"}}) {
edges {
node {
title
images {
filename_disk
}
}
}
}
allImageSharp {
edges {
node {
id
fluid {
originalName
...GatsbyImageSharpFluid
}
}
}
}
}
`
export default IndexPage
As the directus api for this site is not public, I have put up a generated code example here (note: only the homepage works)
Apparently, bootstrap carousel expects its items to be a direct child of the carousel. This means that react fragments don't work over here.
Changing this:
return <>
<Carousel.Item key={sharp.node.id}>
<h1>Image</h1>
<Img fluid={sharp.node.fluid} className="d-block w-100" />
</Carousel.Item>
</>
To this solves the issue:
return (
<Carousel.Item key={sharp.node.id}>
<h1>Image</h1>
<Img fluid={sharp.node.fluid} className="d-block w-100" />
</Carousel.Item>
)

Add a top level menu in react-admin

How can i a a top level menu in the appbar between the title and the usermenu ?
I tried something like this, but it do not work :
const MyAppBar = props => <AppBar {...props} userMenu={<MyUserMenu />} ><MyTopMenu /></AppBar>
Assuming you want to create a sub-menu in react-admin, you'll need to create a custom sub-menu component following the nested list technique from material-ui.
You will also need to create and use a custom menu as explained in react-admin's documentation.
An official way provided from the demo of react-admin: https://github.com/marmelab/react-admin/blob/master/examples/demo/src/layout/Menu.tsx (related answer)
Check this new plugin dedicated for this purpose: ra-tree-menu
As the ra-tree-menu package mentioned above by kxo didn't seem to be working well, I had to resort to develop a new package for this which could solve the use-case and further offer much more ease and flexibility for achieving the purpose.
You can check this out: ra-treemenu. A quick example of using it would be something like:
// In App.js
import * as React from 'react';
import { Admin, Resource, Layout } from 'react-admin';
/* Import TreeMenu from the package */
import TreeMenu from '#bb-tech/ra-treemenu';
const App = () => (
<Admin layout={(props) => <Layout {...props} menu={TreeMenu} />} >
{/* Dummy parent resource with isMenuParent options as true */}
<Resource name="users" options={{ "label": "Users", "isMenuParent": true }} />
{/* Children menu items under parent */}
<Resource name="posts" options={{ "label": "Posts", "menuParent": "users" }} />
<Resource name="comments" options={{ "label": "Comments", "menuParent": "users" }} />
{/* Dummy parent resource with isMenuParent options as true */}
<Resource name="groups" options={{ "label": "Groups", "isMenuParent": true }} />
{/* Children menu items under parent */}
<Resource name="members" options={{ "label": "Members", "menuParent": "groups" }} />
</Admin>
);
export default App;

Nativescript ActionBar custom component

I am trying to create a custom component as described here in order to reuse the action bar and its logic in different places of my app.
Here is what I have setup the component:
/components/header/header.xml
<ActionBar title="Title" class="{{ 'mode' == dark ? 'bg-dark' : 'bg-white' }}" loaded="loaded">
</ActionBar>
/components/header/header.ts
exports.loaded = (args) => {
let page = <Page> args.object;
let pageObservable = new Observable({
'mode' : page.get('mode')
});
page.bindingContext = pageObservable;
}
I then try to use the component calling it like this :
some_view.xml
<Page
xmlns="http://schemas.nativescript.org/tns.xsd"
xmlns:header="components/header">
<header:header mode="dark"/>
<StackLayout>..</StackLayout>
...
</Page>
However, navigating to `some-view.xml' I get the following error:
Calling js method onCreateView failed
TypeError: Cannot read property frame of 'undefined'
File "data...../ui/action-bar/action-bar.js" line: 146
Am I doing something wrong?
Have you succeded in creating a custom component based on ActionBar?
Perhaps the problem is that you are trying to get Page instance in the loaded method in your /components/header/header.ts file. args will return you reference to the ActionBar instead of Page. On other hand while using TypeScript the events should be defined like this export function loaded(args){...}. In the above-given code you are using JavaScript syntax. I am attaching sample code, where has been shown, how to create custom component.
component/action-bar/action-bar.xml
<ActionBar loaded="actionbarLoaded" title="Title" icon="">
<NavigationButton text="Back" icon="" tap="" />
<ActionBar.actionItems>
<ActionItem icon="" text="Left" tap="" ios.position="left" />
<ActionItem icon="" text="Right" tap="" ios.position="right" />
</ActionBar.actionItems>
</ActionBar>
component/action-bar/action-bar.ts
export function actionbarLoaded(args){
console.log("actionbar loaded");
}
main-page.xml
<Page xmlns="http://schemas.nativescript.org/tns.xsd" navigatingTo="navigatingTo" xmlns:AB="component/action-bar">
<Page.actionBar>
<AB:action-bar />
</Page.actionBar>
<StackLayout>
<Label text="Tap the button" class="title"/>
<Button text="TAP" tap="{{ onTap }}" />
<Label text="{{ message }}" class="message" textWrap="true"/>
</StackLayout>
</Page>
main-page.ts
import { EventData } from 'data/observable';
import { Page } from 'ui/page';
import { HelloWorldModel } from './main-view-model';
// Event handler for Page "navigatingTo" event attached in main-page.xml
export function navigatingTo(args: EventData) {
// Get the event sender
let page = <Page>args.object;
page.bindingContext = new HelloWorldModel();
}

Resources