StatusBar backgroundColor removed after pressing back button (android) - react-native

I'm using the StatusBar component in react native (Android). Here is an example code from my App.js component:
import React, { Component } from 'react';
import { View, StatusBar } from 'react-native';
import { RootNavigator } from './components/Router';
export default class MainApp extends Component {
render() {
return (
<View style={{flex: 1}}>
<StatusBar backgroundColor='black' barStyle="light-content"/>
<RootNavigator />
</View>
);
}
}
The StatusBar is working properly when you launch the app, when you navigate through the entire app and when put in background and then return.
It's NOT working when exiting the app by pressing back button. When you launch the app again, the statusbar backgroundColor is suddenly grey (default color).
Is this a known bug or something? I can't figure out how to fix this.

Alright, shortly after submitting the question I found out about another strategy, using imperative API. I avoided it at first since according to official documentation:
For cases where using a component is not ideal, there
is also an imperative API exposed as static functions on the
component. It is however not recommended to use the static API and the
component for the same prop because any value set by the static API
will get overriden by the one set by the component in the next render.
Here is my revised code:
import React, { Component } from 'react';
import { View, StatusBar } from 'react-native';
import { RootNavigator } from './components/Router';
export default class MainApp extends Component {
componentWillMount() {
StatusBar.setBackgroundColor('black');
}
render() {
return (
<View style={{flex: 1}}>
<StatusBar backgroundColor='black' barStyle="light-content"/>
<RootNavigator />
</View>
);
}
}
It seems like this works properly now. When I press the back button and launch the app again the statusbar remains black. I won't declare this as the correct answer just yet in case someone has an explanation why this happens or a better solution.
Edit: This also appears to work only 90% of the time or so. I've noticed, once in a while, when pressing back button and returning the statusbar remained grey. It is absolutely boggling at this point, I suppose componentWillMount isn't always triggered?
Edit2: After switching to componentDidMount instead of componentWillMount as suggested, it seems to be working 100% of the time now.

Related

Icons not showing in my Expo-based React Native App

I have the following code:
import React, { useEffect, useState } from 'react';
import { View } from 'react-native';
import { FontAwesome } from '#expo/vector-icons';
import styles from './styles';
export default function LiveCalls( { navigation }) {
return (
<View>
<FontAwesome name="search" size={204} color="black" />
</View>
);
}
My app runs okay. I'm not getting an errors or warnings. But – no icons are showing. Not even a mysterious "X", where the icon should be. Just nothing. Empty space. Nada. Zilch.
I did check the #expo folder in my node_modules directory to make sure that it's in there... and it is.
I also double checked my icon name, to make sure there was an actual icon in the icon set that I was using.
Additionally, I've tried changing sizes (thinking it might just be super tiny), colors (thinking it might be defaulting to transparent or something), and nothing seems to work.
Any idea what the problem is?

React Navigation: "Cannot Add a child that doesn't have a YogaNode to a parent without a measure function" when using Custom Navigators

I'm trying to make the UI for my app in the below picture:
My App's UI
I follow the instruction of React Navigation to make the Custom Navigator according to the UI but it doesn't work in Android. The red screen appears with the message "Cannot Add a child that doesn't have a YogaNode to a parent without a measure function". Here is my code:
import React, { Component } from 'react';
import { createStackNavigator } from 'react-navigation';
import TabAboutScreen from './TabAbout';
import TabMyLessonScreen from './TabMyLesson';
import TabTeacherScreen from './TabTeacher';
import { ScrollView, View, Text } from '../../../components';
import TabNavigator from './TabNavigator';
import TopBar from './TopBar';
import styles from './styles';
import CourseHeader from './CourseHeader';
import theme from '../../../theme';
import i18n from '../../../i18n';
export const CourseDetailStackNavigator = createStackNavigator({
TabAbout: TabAboutScreen,
TabMyLesson: TabMyLessonScreen,
TabTeacher: TabTeacherScreen,
}, {
headerMode: 'none',
initialRouteName: 'TabAbout',
});
export default class TabCourseDetail extends Component {
static router = CourseDetailStackNavigator.router;
constructor(props) {
super(props);
this._handleOnBackButtonPress = this._handleOnBackButtonPress.bind(this);
}
_handleOnBackButtonPress() {
// do something
}
render() {
return (
<View style={styles.container}>
<TopBar textButton={i18n.t('CMBack')} title={i18n.t('CDCourseDetail')} onPress={this._handleOnBackButtonPress} />
<ScrollView
style={styles.scrollContainer}
stickyHeaderIndices={[1]}
showsVerticalScrollIndicator={false}
alwaysBounceVertical={false}
>
<CourseHeader />
<TabNavigator />
<View style={styles.test}>
<CourseDetailStackNavigator navigation={this.props.navigation} />
</View>
</ScrollView>
</View>
);
}
}
My evironment: react-navigation: 2.12.1, react-native: 0.55.4
I found out that the problem was that I put inside component by following the document of react navigation. It works well in iOS but doesn't work in Android.
Have you ever faced this problem. I'm looking forward to your solutions. Best regard.
Make sure you have not left any commented code in the return method and also have not left any text (string) without Text tag of react native.

React native dynamic style without re render the whole component

Is this conditional styling below still works with react native?
style={[styles.base, this.state.active && styles.background]}
When the component is mounted, the active state is set to false.
The screen has a button to change the active state to true. Then, I would expect the background style to be displayed. But it is not the case unless the page reload.
Any thought ?
Thanks
It sounds like you'd be interested in using the Animated Module from react-native. By using the Animated module, you can have styles that change or animate. You could also use LayoutAnimation. You should read the Animation Documentation and LayoutAnimation documentation.
You can start off by using LayoutAnimation and see if that does what you need. It's quick to set up!
Here's an example:
import React, { Component} from 'react';
import { View, LayoutAnimation, UIManager, Platform } from 'react-native';
class MyComponent extends Component {
constructor(props) {
super(props);
if (Platform.OS === 'android') {
UIManager.setLayoutAnimationEnabledExperimental(true);
}
componentWillUpdate() {
LayoutAnimation.spring() // automatimagically animates style changes
}
render() {
<View style={[styles.base, this.state.active && styles.background]}>
</View>
}
}

React.Children.only expected to receive a single React element child

import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View
} from 'react-native';
import Login from './js/components/Login';
import userReducers from './js/reducers/user';
import { createStore, combineReducers } from 'redux';
import { Provider } from 'react-redux';
let store = createStore(combineReducers({userReducers}));
class App extends Component {
render() {
return (
<Login />
);
}
}
export default class Testextends Component {
render() {
return (
<Provider store = {store}>
<App />
</Provider>
// <View>
// <Text>jhdgf</Text>
// </View>
);
}
}
AppRegistry.registerComponent('Test', () => Test);
It gives me following error:
I'm trying one basic example of react-native with redux. If I remove TouchableHighlight also , the error still persists. Any ideas what is wrong here?
Its doesn't seems you're doing something wrong, on the code pasted, are you sure the error came from this part of your code ?
Maybe try to put between () your TouchableHighlight component, but I don't think that's going to change something...
Or try a ternary rather than a binary operation.
Also be sure that you import TouchableHighlight and Text from react-native.
Try to delete all not necessary white space
<View>{ !this.props.user.loggedIn &&
<TouchableHighlight onPress={this.onLoginButtonPress}>
<Text>Login</Text>
</TouchableHighlight>
}</View>
Because in the following example
<View> {...}</View>
you have two children: first white space and second all in curved brackets.
Had the same issue with the following React Native code:
import {Link} from 'react-router-native'
<Link to={props.url}>{props.title}</Link>
Spend few hours trying to understand why the similar code works in WEB but not in native view. There is no viable error messaging or hints from the React Native runtime on which component causes this failure, so it's insanely hard to identify the issue.
Managed to fix this crash by doing the following:
import {Link} from 'react-router-native'
import {Text} from "react-native";
<Link to={props.url}><Text>{props.title}</Text></Link>
Looks like the title text was treated as multiple elements, so we ended up with such an error.
This is not a solution for the subject. But, because there are so many ways to fail with this error in React Native, it may be useful to put this another example of such a crash for those who Googled and ended here.
First off, "export default class Testextends Component" should actually be "export default class Test extends Component"
the reason why that error is thrown is because the Provider component takes only one element.
for Example:
wrong:
<provider store = {store}>
<div/>
<div/>
<provider>
correct:
<provider store = {store}>
<App/>
<provider>
which you did correctly, if you commented the component. Try the class error and see if it works.

Change view in Navigator in React Native

I'm new to react native.
I was using NavigatorIOS but it was too limiting so I'm trying to use Navigator. In NavigatorIOS I can change a view by calling this.props.navigator.push() but it doesn't work in Navigator, it seems to be structured differently. How do I change views in using Navigator?
That's the minimal working navigator - it can do much more (see at the end):
You need your main "navigator" view to render Navigator component
In the Navigator you need to specify how you should render scenes for different routes (renderScene property)
In this "renderScene" method you should render View (scene) based on which route is being rendered. Route is a plain javascript object, and by convention scenes can be identified by "id" parameter of the route. For clarity and separation of concerns I usually define each scene as separate named component and use the name of that components as "id", though it's just a convention. It could be whatever (like scene number for example). Make sure you pass navigator as property to all those views in renderScene so that you can navigate further (see below example)
When you want to switch to another view, you in fact push or replace route to that view and navigator takes care about rendering that route as scene and properly animating the scene (though animation set is quite limited) - you can control general animation scheme but also have each scene animating differently (see the official docs for some examples). Navigator keeps stack (or rather array) of routes so you can move freely between those that are already on the stack (by pushing new, popping, replacing etc.)
"Navigator" View:
render: function() {
<Navigator style={styles.navigator}
renderScene={(route, nav) =>
{return this.renderScene(route, nav)}}
/>
},
renderScene: function(route,nav) {
switch (route.id) {
case "SomeComponent":
return <SomeComponent navigator={nav} />
case "SomeOtherComponent:
return <SomeOtherComponent navigator={nav} />
}
}
SomeComponent:
onSomethingClicked: function() {
// this will push the new component on top of me (you can go back)
this.props.navigator.push({id: "SomeOtherComponent"});
}
onSomethingOtherClicked: function() {
// this will replace myself with the other component (no going back)
this.props.navigator.replace({id: "SomeOtherComponent"});
}
More details here https://facebook.github.io/react-native/docs/navigator.html and you can find a lot of examples in Samples project which is part of react-native: https://github.com/facebook/react-native/tree/master/Examples/UIExplorer
I find that Facebook examples are either to simplistic or to complex when demonstrating how the Navigator works. Based on #jarek-potiuk example, I created a simple app that will switch screens back and forth.
In this example I'm using: react-native: 0.36.1
index.android.js
import React, { Component } from 'react';
import { AppRegistry, Navigator } from 'react-native';
import Apple from './app/Apple';
import Orange from './app/Orange'
class wyse extends Component {
render() {
return (
<Navigator
initialRoute={{screen: 'Apple'}}
renderScene={(route, nav) => {return this.renderScene(route, nav)}}
/>
)
}
renderScene(route,nav) {
switch (route.screen) {
case "Apple":
return <Apple navigator={nav} />
case "Orange":
return <Orange navigator={nav} />
}
}
}
AppRegistry.registerComponent('wyse', () => wyse);
app/Apple.js
import React, { Component } from 'react';
import { View, Text, TouchableHighlight } from 'react-native';
export default class Apple extends Component {
render() {
return (
<View>
<Text>Apple</Text>
<TouchableHighlight onPress={this.goOrange.bind(this)}>
<Text>Go to Orange</Text>
</TouchableHighlight>
</View>
)
}
goOrange() {
console.log("go to orange");
this.props.navigator.push({ screen: 'Orange' });
}
}
app/Orange.js
import React, { Component, PropTypes } from 'react';
import { View, Text, TouchableHighlight } from 'react-native';
export default class Orange extends Component {
render() {
return (
<View>
<Text>Orange</Text>
<TouchableHighlight onPress={this.goApple.bind(this)}>
<Text>Go to Apple</Text>
</TouchableHighlight>
</View>
)
}
goApple() {
console.log("go to apple");
this.props.navigator.push({ screen: 'Apple' });
}
}
I was having the same trouble, couldn't find a good example of navigation. I wanted the ability to control views to go to a new screen but also have the ability to go back to the previous screen.
I used the above answer by Andrew Wei and created a new app then copied his code. This works well but the .push will keep on creating new layers over each other (Apple > Orange > Apple > Orange > Apple > Orange etc.). So I used .pop in the Orange.js file under goApple() instead of .push.
This works like a "back" button now, which was what I was looking for, while teaching how to navigate to other pages.