How to remove double header with react-navigation? - react-navigation

My React Native 0.61.5 uses react-navigation 5.1. Here is the root navigation code:
const BTab = createBottomTabNavigator();
const Stack = createStackNavigator();
export default function App() {
//const Appscreen = () => (<AppScreen data={data}/>);
return (
<NavigationContainer>
<Stack.Navigator InitialRouteName="Splash">
<Stack.Screen name="Splash" component={SplashScreen}}/>
<Stack.Screen name="App" component={AppScreen} } />
</Stack.Navigator>
</NavigationContainer>
);
}
The component AppScreen return a stack like this:
return (
<NavigationContainer independent={true}>
<BTab.Navigator>
<BTab.Screen name="Event" component={Eventstack} />
<BTab.Screen name="Group" component={Groupstack} />
<BTab.Screen name="Contact" component={Contactstack} />
</BTab.Navigator>
</NavigationContainer>
);
I notice that on the screen there are double header:
How can I remove the App header and only keep the Group?

add with the screen that you want to hide the header.
options= {{
headerShown: false
}}
For further reading, kindly have a look at https://reactnavigation.org/docs/stack-navigator/#headershown

Related

React Native Stack Navigator passing props

I want to pass some props (value) to another page and I'm using stackNavigator
App.js:
import Insert from "./components/pages/Insert";
import ViewData from "./components/pages/ViewData";
const Stack = createStackNavigator();
NavigationContainer>
<Stack.Navigator headerMode={false}>
<Stack.Screen name="Insert Your data" component={Insert} />
<Stack.Screen name="ViewData" component={ViewData} />
</Stack.Navigator>
</NavigationContainer>
Insert.js
const Insert = ({ props, navigation: { navigate } }) => {
const [enteredName, setEnteredName] = useState();
const [enteredSurname, setEnteredSurname] = useState();
const sendValues = (enteredName, enteredSurname) => {
setEnteredName(enteredName);
setEnteredSurname(enteredSurname);
navigate("ViewData", {
name: enteredSurname,
surname: enteredSurname
});
};
...
<View>
<Button
title="Submit"
onPress={() => sendValues(enteredName, enteredSurname)}
/>
ViewData.js
const ViewData = ({props, navigation: { goBack } }) => {
let name = enteredName;
console.log(name); /// I always get undefined
return (
<View style={{ flex: 1, alignItems: "center", justifyContent: "center" }}>
<Text>Here {name}</Text>
<Button onPress={() => goBack()} title="Edit Data" />
</View>
);
};
When I Submit I'm always getting undefined into the console.
For sure I'm mistaking somewhere.
Any idea?
Thanks!!
Refer to https://reactnavigation.org/docs/hello-react-navigation/#passing-additional-props
Use a render callback for the screen instead of specifying a component
prop:
<Stack.Screen name="Home">
{props => <HomeScreen {...props} extraData={someData} />}
</Stack.Screen>
You can change like this
import Insert from "./components/pages/Insert";
import ViewData from "./components/pages/ViewData";
const Stack = createStackNavigator();
<NavigationContainer>
<Stack.Navigator headerMode={false}>
<Stack.Screen name="Insert Your data">
{props => (<Insert {...props} extraData={data}/>)}
<Stack.Screen name="ViewData" component={ViewData} />
</Stack.Navigator>
</NavigationContainer>
Reading your code it seems that you want to pass some params to the render component when navigate.
Refer to https://reactnavigation.org/docs/route-prop , the params from
navigation.navigate(routeName, params)
are passed to the screen render component as propriety of the route object. So in your case it should work:
let name = props.route.params.name;

Multiple drawers in react-navigation 5.0

I wrote below code to make multiple side menus but it occurred error
Another navigator is already registered for this container. You likely have multiple navigators under a single "NavigationContainer" or "Screen". Make sure each navigator is under a separate "Screen" container.
However I've tried to find the Container for multiple drawers but no luck.
What should I do?
Thanks in advance.
import React from 'react';
import { AppLoading } from 'expo';
import * as Font from 'expo-font';
import { Ionicons } from '#expo/vector-icons';
import { createDrawerNavigator } from '#react-navigation/drawer';
import { NavigationNativeContainer } from '#react-navigation/native';
import { Container, Text, Button } from 'native-base';
import 'react-native-gesture-handler'
function BlankScreen({ navigation }) {
return (
<Text>Blank</Text>
);
}
function HomeScreen({ navigation }) {
return (
<Container style={{ flex: 1, flexDirection: 'column-reverse' }}>
<Button onPress={() => navigation.navigate('Menu')}>
<Text>Go to Menu</Text>
</Button>
<Button onPress={() => navigation.navigate('Favorit')}>
<Text>Go to Favorit</Text>
</Button>
</Container>
);
}
function MenuScreen({ navigation }) {
return (
<Container style={{ flex: 1, flexDirection: 'column-reverse' }}>
<Button onPress={() => navigation.goBack()}>
<Text>Go back home</Text>
</Button>
</Container>
);
}
function FavoritScreen({ navigation }) {
return (
<Container style={{ flex: 1, flexDirection: 'column-inverse' }}>
<Button onPress={() => navigation.goBack()}>
<Text>Go back home</Text>
</Button>
</Container>
);
}
const DrawerL = createDrawerNavigator();
const DrawerR = createDrawerNavigator();
export default function App() {
return (
<Container>
<NavigationNativeContainer>
<DrawerL.Navigator initialRouteName="Home" drawerPosition="left">
<DrawerL.Screen name="Home" component={HomeScreen} />
<DrawerL.Screen name="Menu" component={MenuScreen} />
<DrawerL.Screen name="Favorit" component={FavoritScreen} />
</DrawerL.Navigator>
<DrawerR.Navigator initialRouteName="Blank" drawerPosition="right">
<DrawerR.Screen name="Blank" component={BlankScreen} />
<DrawerR.Screen name="Menu" component={MenuScreen} />
<DrawerR.Screen name="Favorit" component={FavoritScreen} />
</DrawerR.Navigator>
</NavigationNativeContainer>
</Container>
);
The way you wrote it won't work, because consider this: you've 2 drawers, one has initial route as "Home", and other as "Blank". Which one should be rendered?
Here, you need to follow the same approach as React Navigation 4, put one drawer inside another:
function HomeStack() {
return (
<Stack.Navigator screenOptions={{ animationEnabled: false }}>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Menu" component={MenuScreen} />
<Stack.Screen name="Favorit" component={FavoritScreen} />
</Stack.Navigator>
)
}
function RightDrawer() {
return (
<DrawerR.Navigator initialRouteName="Home" drawerPosition="right">
<DrawerR.Screen name="Home" component={HomeStack} />
<DrawerR.Screen name="Menu" component={MenuScreen} />
<DrawerR.Screen name="Favorit" component={FavoritScreen} />
</DrawerR.Navigator>
)
}
function LeftDrawer() {
return (
<DrawerL.Navigator initialRouteName="RightDrawer" drawerPosition="left">
<DrawerL.Screen name="RightDrawer" component={RightDrawer} />
</DrawerL.Navigator>
);
}
function App() {
return (
<NavigationNativeContainer>
<LeftDrawer />
</NavigationNativeContainer>
)
}
Since your left drawer won't show the screens that you have in Stack, you will need to provide a custom component for your drawer which lists the screens: https://reactnavigation.org/docs/en/next/drawer-navigator.html#providing-a-custom-drawercontent

How to change value of input in Admin on Rest from another component in Create form?

I've reduced this to a very simple case for ease of discussion. I have a simple create form with 1 field and 1 button. I would like the button to set the value of the TextInput to "Hello" without submitting the form. How is this possible in admin on rest? eg:
export const TestCreate = (props) => (
<Create title={<TestTitle />} {...props}>
<SimpleForm>
<TextInput source="title" />
<TitleSetterButton />
</SimpleForm>
</Create>
);
Been struggling with this for a while - it should be simple so hopefully there's an easy answer.
I was able to setup a Sample form using their example application
// in src/posts.js
import React from 'react';
import { List, Edit, Create, Datagrid, ReferenceField, TextField, EditButton, DisabledInput, LongTextInput, ReferenceInput, required, SelectInput, SimpleForm, TextInput } from 'admin-on-rest';
import FlatButton from 'material-ui/FlatButton';
export const PostList = (props) => (
<List {...props}>
<Datagrid>
<TextField source="id" />
<ReferenceField label="User" source="userId" reference="users">
<TextField source="name" />
</ReferenceField>
<TextField source="title" />
<TextField source="body" />
<EditButton />
</Datagrid>
</List>
);
const PostTitle = ({ record }) => {
return <span>Post {record ? `"${record.title}"` : ''}</span>;
};
export class Testing extends React.Component {
render() {
return <input type="text" />
}
}
export class PostCreate extends React.Component {
componentDidMount() {
console.log(this)
}
constructor(props) {
super(props);
this.handleCustomClick = this.handleCustomClick.bind(this);
// this.fieldOptions = this.fieldOptions.bind(this);
}
handleCustomClick() {
this.fields.title.handleInputBlur("tarun lalwani");
this.fields.body.handleInputBlur("this is how you change it!");
}
render () {
let refOptions = {ref: (e) => {
if (e && e.constructor && e.props && e.props.name) {
this.fields = this.fields || {};
this.fields[e.props.name] = e;
}
}}
return (
<Edit title={<PostTitle />} {...this.props}>
<SimpleForm>
<DisabledInput source="id" />
<ReferenceInput label="User" source="userId" reference="users" validate={required}>
<SelectInput optionText="name" />
</ReferenceInput>
<TextInput source="title" options={refOptions}/>
<LongTextInput source="body" options={refOptions}/>
<FlatButton primary label="Set Value" onClick={this.handleCustomClick} />
</SimpleForm>
</Edit>
);
}
}
Before click of the button
After clicking Set Value
And then after clicking Save you can see the actual changed values get posted

Force update of a ReferenceManyField from an custom action in admin-on-rest

I have the following Edit component:
const UserEdit = (props) => (
<Edit {...props}>
<TabbedForm>
<FormTab label="Main">
<TextInput source="var1" />
<TextInput source="var2" />
<TextInput source="var3" />
</FormTab>
<FormTab label="Images">
<ImageUploadComponant />
<ReferenceManyField label="Images" reference="images" target="user_id">
<Datagrid>
<ImageField source="url" />
<DeleteButton />
</Datagrid>
</ReferenceManyField>
</FormTab>
</TabbedForm>
</Edit>
);
The ImageUploadComponant is juste a componant that enable the user to upload a file, and it creates a new object on the API related to the ReferenceManyField :
class ImageUpload extends Component {
onDrop = async files => {
/* Uploading the file */
};
render() {
return (
/* A componant with an upload field */
);
}
}
ImageUpload.propTypes = {
push: PropTypes.func,
record: PropTypes.object,
showNotification: PropTypes.func,
};
export default connect(null, {
showNotification: showNotificationAction,
push: pushAction,
})(ImageUpload);
After the /* Uploading the file */ block, I would like to refresh the ReferenceManyField so the fresh uploaded image is shown.
I guess I have to put some kind of redux / sagas message, but I didn't manage to perform it. Any idea ?

How can I create a SaveButton which returns to me to a special URL

I know that I can use an url as redirect parameter for an SaveButton like this:
const ResourcePropertyEditToolbar = props => <Toolbar {...props} >
<SaveButton />
<SaveButton label="save and resource" redirect={"/resource/21"}
submitOnEnter={false} raised={false} />
</Toolbar>;
As you see the "/resource/21" is hard coded and it works (for this entry ;-) How can I dynamically create the url? The value itself is included in the current data set which is edited, like this:
export const ResourcePropertyEdit = (props) => (
<Edit {...props} >
<SimpleForm toolbar={<ResourcePropertyEditToolbar />}>
<NumberInput source="position" defaultValue="1"/>
<TextInput source="property_name" validate={required}/>
<ReferenceInput label="Resource" source="fk_resource"
reference="resource">
<AutocompleteInput optionText="shortname"/>
</ReferenceInput>
</SimpleForm>
</Edit>
);
It is the value of the selected fk_resource.
Here is the code snippet for the base Form with the ReferenceManyField Entry, the target is to jump back to this view after editing a resource_property.
export const ResourceEdit = (props) => (
<Edit {...props}>
<SimpleForm>
<TextInput source="shortname" validate={required}/>
<ReferenceManyField target="fk_resource"
reference="resource_property" >
<Datagrid>
<NumberField source="position"/>
<TextField source="property_name"/>
<ReferenceField label="Property" source="fk_property" reference="property" allowEmpty>
<TextField source="shortname"/>
</ReferenceField>
<EditButton/>
</Datagrid>
</ReferenceManyField>
</SimpleForm>
</Edit>
);
Thanks for any help
The current data set is called the record in AOR. If the URL is in the record you can access it simply by
const ResourcePropertyEditToolbar = props => <Toolbar {...props} >
<SaveButton />
<SaveButton label="save and resource" redirect={props.record.url ? props.record.url : null}
submitOnEnter={false} raised={false} />
</Toolbar>

Resources