Render global footer in react-native-router-flux 3.x - react-native

I have an app where on all scenes I want to render a global navigation footer at the bottom of the screen. This was a very easy thing to do in RNRF 2.x with the footer prop, but I'm having quite a lot of trouble implementing it in 3.x since the footer prop does not exist anymore. Anyone know how to go about doing this?

You can do this with only React Native. Just wrap your old main component in a new View that contains the old main component and the footer. Then the footer will always be shown.
Assuming you have a main component named MainComponent in a file path/to/main/component.js:
// path/to/main/component.js
export default class MainComponent extends React.Component {
...
}
Just change it to this:
// path/to/main/component.js
class MainComponent extends React.Component {
...
}
export default () => (
<View styles={styles.newMainComponent}>
<MainComponent />
<GlobalFooter />
</View>
);
You may need to move some styles from your old main component to the new view that wraps it.

Related

How to change tab bar icon programmatically in React Native from another component?

I want to change the bottom tab icon from my home screen or another component. I don't know how to achieve it, in Android I can use interface and EventBus but I'm not sure there something equivalent in React-Native, I tried using redux store but didn't work for me I have 5 buttons in the bottom tab bar I want to change the the centre button when I have some check fulfilled from the backend in my home screen.How can I change it from the home screen? any help will be appriciated thank you in advance
You can use ref to access method of other component.
https://facebook.github.io/react-native/docs/direct-manipulation
EDIT:
Sorry for the late reply, the ref method works best if both components are siblings.
Here see this code:
class TestPage1 extends Component {
constructor(props) {
super(props)
this.state={}
};
onDoSomething=()=>{
this.comp2_ref.callThisMethod()
}
render() {
return (
<View>
<Comp1 onDoSomething={this.onDoSomething}/>
<Comp2 onRef={(ref)=>{
this.comp2_ref=ref;
})/>
</View>
)
}
}
class Comp1 extends Component{
render(){
return(<View>
<Button onPress={()=>{
typeof
this.props.onDoSomething==='function'&&this.props.onDoSomething()
}}></Button></View>)
}
}
class Comp2 extends Component{
callThisMethod=()=>{
//do something for comp2 that will be called by comp 1
}
render(){
return(<View></View>)
}
componentDidMount(){
typeof this.props.onRef==='function'&&this.props.onRef(this);
}
}
If they are separate then you can also use consumer and provider concept.

How can we create a react-native component which can be displayed with .show() method

I am looking for pointers where I can start from.
I want to create a react native feedback form which can be displayed with .show method.
for eg:
export class FeedbackComponent extends React.component{
show() {
// define this method in a way so that can be called from outside as FeedbackComponent.show()
// which eventually create a new screen with below rendered View
}
render (){
return <View>Feedback Form</View>
}
}
I should be able to use this Component in any other component as
import FeedbackComponent from './FeedbackComponent'
new FeedbackComponent.show()
I would always start with considering the application state. UI in React is updated whenever the State of our components changes.
In your case I would have to think of the parent context in which your feedback form will need to be displayed. In its simplest form, this context will likely be a parent screen-component within which your FeedbackForm component is either shown or hidden.
I've made a Snack of a simple implementation you can find it here: https://snack.expo.io/#stephos_/show-feedback-form
In my case, the App component is the parent screen-component within which we need to render or not render a FeedbackForm Component.
So I would start with adding the relevant state property to the App (parent screen) component like so:
state = {
feedbackFormVisible : false
}
I would then define a method within the same parent class in order to toggle the state when we need to like so:
handleFeedbackFormVisibility = () => this.setState(prevState => ({feedbackFormVisible:!prevState.feedbackFormVisible}))
This handler takes in the previous state in our parent component and toggles the value of the feedbackFormVisible property (i.e. from false to true).
In my case, I call this handler every time we press a Button component like so:
<Button title="Give Feedback" onPress={this.handleFeedbackFormVisibility}/>
You could however trigger the same handler and update the state of the parent component in any other way (i.e. after a timer expires or after a specific scroll point is passed).
The App Component's render method will then decide if the FeedbackForm component should be displayed based on the value of the feedbackFormVisible in our App Component's state. We achieve this by wrapping our FeedbackForm component within an Elvis Conditional within the render method which will return the the appropriate UI (i.e. either with a visible feedback form or not):
{ this.state.feedbackFormVisible ? () : null}
Below the full App component code:
import * as React from 'react';
import { Text, View, StyleSheet, Button } from 'react-native';
import FeedbackForm from './components/FeedbackForm';
export default class App extends React.Component {
state = {
feedbackFormVisible : false
}
handleFeedbackFormVisibility = () => this.setState(prevState => ({feedbackFormVisible:!prevState.feedbackFormVisible}))
render() {
return (
<View style={styles.container}>
<Text style={styles.paragraph}>
This is the App Parent Component
</Text>
{
this.state.feedbackFormVisible ?
(<FeedbackForm />)
: null
}
<Button title="Give Feedback" onPress={this.handleFeedbackFormVisibility}/>
</View>
);
}
}
And below the Feedback Component code (Notice that the shown/hidden logic is actually handled in the parent component not in here):
import * as React from 'react';
import { Text, View, StyleSheet } from 'react-native';
export default class FeedbackForm extends React.Component {
render() {
return (
<View style={styles.container}>
<Text style={styles.paragraph}>
This is the feedback form!
</Text>
</View>
);
}
}

How to create and connect a custom component theme for Native Base

I'm using Native Base 2.0+, the themes are ejected and using StyleProvider I am able to tweak and customize any Native Base component according to my theme, no problem.
Following the docs, it's stated that to add themes to a custom component we should define a namespace for said component and merge it with the instantiated styling as well. Code example below:
import React, { Component } from 'react'
import { Header, Left, Body, Right, Button, Title, Text, connectStyle } from 'native-base'
import Colors from '../Themes/Colors'
import ApplicationStyles from '../Themes/ApplicationStyles'
class NBHeader extends Component {
render () {
const styles = this.props.style
return (
<Header style={styles.header}>
<Left>
<Button transparent>
<Text style={styles.headerBackButton}>
{'< Back'}
</Text>
</Button>
</Left>
<Body>
<Title>Login</Title>
</Body>
<Right />
</Header>
)
}
}
export default connectStyle('CustomComponents.Header', ApplicationStyles)(NBHeader)
In this case, namespace for the component is 'CustomComponents.Header'. Then, we use StyleProvider to connect the Theme:
import React, { Component } from 'react';
import { StyleProvider } from 'native-base';
class CustomComponent extends Component {
render() {
return (
// connect styles to props.style defined by the theme
const styles = this.props.style;
<StyleProvider style={customTheme}>
Your Custom Components
</StyleProvider>
);
}
}
// Define your own Custom theme
const customTheme = {
'yourTheme.CustomComponent': {
// overrides CustomComponent style...
}
};
Since I've ejected the theme, I entered the new namespace for the Custom Component in NB's Theme file, so it should already be added and cascaded using StyleProvider.
So for instance, if I want the header to be 'red' and have a padding of '10' due to theming rules, I add those as default props of 'CustomComponents.Header' and forget about it, it will always be applied to the component as long as the StyleProvider is cascading themes.
The problem is I cannot get this defined Custom Component's default theme to be applied. I don't know if it's a problem with my code or how Native Base works. Any help would be appreciated and I can provide further code if needed.

ExNavigator in react-native can't find Router

My routes were working fine with the built-in NavigatorIOS, but I wanted to add a custom font to the navigation so I decided to go with ExNavigator. I'm open to other component solutions, but first here is my problem:
From my initial route, the user is supposed to go to a detail view onPress. The initial route is loading, but the detail view is not working with ExNavigator.
I made an object for the router following exponent's docs. When the onPress event is triggered, I get an error: Can't find variable: Route
Here are some code snippets
app.js
class app extends React.Component {
render() {
return (
<ExNavigator
style={styles.container}
translucent={false}
initialRoute={
Router.getHomeRoute()
}/>
);
}
}
let router = {...}
export default Router;
main.js
<TouchableHighlight underlayColor={'#f3f3f2'}
onPress={()=>this.selectRow(row)}>
selectRow: function(row){
row = {row};
let route = Router.getDetailRoute(row);
this.props.navigator.push(route);
}
for detail.js i'm just including NavigatorIOS.
I get a react error if I try and put the router in any other file but app.js.

How to reference custom components in react-native?

So I have a custom component like this:
class MyComponent extends React.Component {
render() {
return (
<TouchableHighlight style={this.props.buttonStyle}>
<Text style={styles.buttonText}>Button</Text>
</TouchableHighlight>
);
}
}
And I use the component like this:
class RootView extends React.Component {
render() {
return (
<View>
<MyComponent/>
<MyComponent/>
</View>
);
}
}
The RootView is resizable. What I want to do is shrinking it's children MyComponent when RootView is small enough. And I need to shrink each MyComponent at a time: when RootView is small enough, shrink the first MyComponent, and when the first MyComponent reach a minimal size, shrink the second MyComponent.
I know there's refs in react-native, but it does not seem to work for custom component.
You can add a ref to a custom component:
<Separator ref='sep' style={styles.offsetSeparator} />
So you should be able to do what you need.
However, when you find yourself having a strong dependency between different components, it means that it's probably a good time to start using Flux or something similar and then hold the data in a Store which will hold all the information needed for all 3 components. More about Flux here: https://facebook.github.io/flux/