React native dynamic style without re render the whole component - react-native

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>
}
}

Related

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.

StatusBar backgroundColor removed after pressing back button (android)

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.

Using Fade-in Animation from #shoutem/animation on s3 image

I am displaying my images from S3. I would like them to fade-in on load. This seems like it should be a simple request. Can someone give me some guidance on this, if possible?
Thanks!
You can just use a TimingDriver to animate the component.
import React from 'react';
import { View, Easing } from 'react-native';
import { TimingDriver, FadeIn } from '#shoutem/animation';
class Screen extends React.Component {
render() {
driver = new TimingDriver({
duration: 400 // 250 by default,
easing: Easing.inOut // Easing.cubic is passed by default
delay: 0 // 0 by default
});
return (
<View>
<FadeIn driver={driver}>
{/* Some components to fade in with time passing */}
</FadeIn>
</View>
)
}
}
You can find out more about the Animation part of the toolkit here.

How to use this.state with react-native?

Hi I'm new to react so bear with me.
Below is my code...
import React from 'react';
import { StyleSheet, Text, View, TouchableHighlight, AsyncStorage} from 'react-native';
export default class App extends React.Component {
constructor(){
super();
this.state = {
myLeader: 'Joe',
};
}
onPress(){
alert({this.state.myLeader}); // 14
}
render() {
return (
<View>
<TouchableHighlight onPress={this.onPress.bind(this)}>
<Text>{this.state.myLeader}</Text>
</TouchableHighlight>
</View>
);
}
}
How to fix this problem?
error message is this. 'this is a reserved word(14.9) at Home.js:14.9'
I want to use {this.state.myLeader} in
onPress(){
alert({this.state.myLeader});
}
I tried 'bind(this)'
Any clue why?
Be careful with your usage of {}. In the context of JSX, {} can be used to "interpolate" a value within it. But if you're writing plain JavaScript code (as in alert({this.state.myLeader})) you don't need to interpolate anything, you just pass the value this.state.myLeader to alert, as in alert(this.state.myLeader).
Regarding the usage of alert within React Native, you'll probably want to follow #kytwb's advise and use Alert.alert.
Try to replace line 14 with:
console.log(this.state.myLeader)
To use Alert with React Native, take a look at the doc.
First, import Alert from react-native:
import { StyleSheet, Alert, Text, View, TouchableHighlight, AsyncStorage} from 'react-native';
Then, change the onPress function:
onPress(){
Alert.alert(this.state.myLeader); // 14
}
Another solution is to forget about the bind and do this:
onPress = () => {
alert({this.state.myLeader}); // 14
}
<TouchableHighlight onPress={this.onPress}>

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.