Conditional header in react-native StackNavigator - ios

I'm trying to control whether or not my StackNavigator header appears via this.props.navigation.state.params.
I have a screen with the following navigationOptions:
static navigationOptions = ( {navigation} ) => ({
header: navigation.state.params.headerConfig,
});
and I navigate to the screen as follows:
<Button
onPress={() => navigate('MyScreen', { headerConfig: _____} ) }
title="Continue"
/>
, where ____ is what I am unsure about. If I put null then the header disappears, but what can I put there if I don't want the header to disappear?
I tried entering HeaderProps instead of ____.
Any help or alternative approaches would be much appreciated.

If you don't want it do disappear then don't set it to null, leave it undefined and you will get the default one.
static navigationOptions = ({navigation}) => {
if (navigation.state.params.hideHeader) {
return {header: null}
}
return {title: 'Home'}
}

Related

React Native RefreshControl not triggering onRefresh on iOS

I've got the following (simplified) setup for my PersonScreen, which navigate to AppointmentScreen:
class PersonScreen {
state = {
refreshing: false,
};
_onRefresh = () => {
this.setState({ refreshing: true });
this._fetchStuff()
.then(() => {
this.setState({ refreshing: false });
};
};
render() {
return (
<View style={CONTAINER}>
<ScrollView
keyboardShouldPersistTaps="handled"
refreshControl={<RefreshControl refreshing={refreshing} onRefresh={this._onRefresh} />}
<ListItem
key={ITEM.id}
title={moment(DATETIME).format(FORMAT))}
onPress={() => {
navigation.navigate('AppointmentScreen', {
appointment: ITEM,
refreshParent: this._onRefresh,
});
}
/>
</ScrollView>
</View>
);
}
}
On the AppointmentScreen you make some choices and then to go back the following is performed:
const { refreshParent } = navigation.state.params;
refreshParent();
navigation.goBack();
The only scenario where this does not work is on iOS. It works as long as I go to PersonScreen and refresh. However, if I go from PersonScreen to AppointmentScreen and back it does trigger the refreshParent (which is essentially _onRefresh), but then any attempts to pull down to trigger the RefreshControls onRefresh function fails. I've also added some console.log in the _onRefresh, but it doesn't even output anything.
If my AppointmentScreen instead looks like this:
const { refreshParent } = navigation.state.params;
//refreshParent();
navigation.goBack();
Everything works. So I'm experiencing that somehow calling refreshParent and then going back makes the following _onRefresh from the RefreshControl in PersonScreen not work.
Does anyone have any ideas why this is the case? As mentioned, I only experience this on iOS, but consistently so on iOS simulator and devices.
Can you create an expo version?
also, your refreshing is refreshing={refreshing} it should be refreshing={this.state.refreshing}

Different tabBar icons in react navigation for selected and unselected state?

I am setting up a tabbar using react navigation in react native. I am unable to setup multiple tabbar icons for selected/unselected state. Any reference or doc would help ?
tabBarIcon callback provides you the focused variable for the same.
static navigationOptions = {
tabBarLabel: 'Home',
tabBarIcon: ({ focused }) => {
const image = focused
? require('../active.png')
: require('../inactive.png')
return (
<Image
source={image}
style={styles.tabIcon}
/>
)
}
}
You can change the icon based on the activeTintColor / inactiveTintColor
static navigationOptions = {
tabBarLabel: 'Notifications',
tabBarIcon: ({ tintColor }) => (tintColor == '#e91e63' ?
<Image
source={require('./activeIcon.png')}
style={[styles.icon, {tintColor: tintColor}]}
/>
:
<Image
source={require('./inactiveIcon.png')}
style={[styles.icon, {tintColor: tintColor}]}
/>
),
tabBarOptions: {
activeTintColor: '#e91e63',
}
};
You can do something like this even if you don't use the tint color.

listview disappeared after setState({ds})

I am confused with the rerender mechanism of listview.
Page 1 have render a listview with two item, then I click 'Add' button, navigate to another page, and add one item to Page 1's datasource, then navigator back.
What I expect to see is Page 1 with three item, but actually is Page 2, listview is disappeared. But if I use mouse/finger touch it, listView come out again with three item.
I have test it on my iphone and simulator
Page 1's source code:
class Market extends Component {
constructor(props) {
super(props)
this.state = {
dataSource: new ListView.DataSource({ rowHasChanged: (r1, r2) => r1 !== r2 }),
}
}
componentDidMount() {
this.refreshListView(this.props.data)
}
componentWillReceiveProps(nextProps) {
this.refreshListView(nextProps.data)
}
refreshListView() {
this.setState({
dataSource: this.state.dataSource.cloneWithRows(data)
})
}
render() {
return (
<ListView
dataSource={this.state.dataSource}
renderRow={this._renderRow}
refreshControl={
<RefreshControl/>
}
/>
)
}
const mapStateToProps = createSelector(
selectData(),
(data) => ({
data,
})
)
export default connect(mapStateToProps)(Market)
Just found something that has fixed mine! try adding removeClippedSubviews={false} to your ListView
https://github.com/facebook/react-native/issues/8607#issuecomment-231371923

Inject JavaScript or CSS into React Native WebView before page renders

I want to hide a header of a specific page that I embed into a React Native WebView. Currently, I use something like this, to dynamically remove the header:
<WebView
... some other props ...
injectedJavaScript={'function hideHead(){document.getElementById("head").style.display="none";};hideHead();'}
/>
Sometimes you can still see the header flashing, so I guess this JavaScript gets evaluated after the page loads in the WebView.
Is it possible somehow to add / inject JavaScript or CSS before the page renders to remove that flashing?
I couldn't find a way to inject JavaScript or CSS before the page loads.
To workaround the flashing problem, I put another View on top of the WebView while it is still in loading state. The onNavigationStateChanged callback can be used to find out whether the page is loaded. The View I put on top simply shows an ActivityIndicatorIOS.
I faced this issue, my solution was like that
render() {
const remove_header = 'header = document.querySelector("header"); header.parentNode.removeChild(header);';
uri = this.props.url
return (
<View style={{flex:1 }}>
{(!this.state.showWebView) && <ActivityIndicator size="large" /> }
<WebView
style={this.state.showWebView ? {flex:1} : {flex: 0} }
source={{uri: uri}}
javaScriptEnabled
injectedJavaScript={'function injectRules() {'remove_header'};injectRules();'}
onNavigationStateChange={(event) => {
if (event.url !== uri) {
this.webview.stopLoading()
Linking.openURL(event.url)
}
}}
onLoadStart={() => {
this.setState({ showWebView: false })
}}
onLoadEnd={() => {
if (!this.state.showWebView ) {
this.setState({ showWebView: true })
}
}}
/>
</View>
)
}
My quick solution was to add a negative marginTop to the WebView to hide the header. By doing this, the header is hidden before the render.
webView: {
...
marginTop: -80,
},

How to change the title of the NavigatorIOS without changing the route in React Native

I have a NavigatorIOS and TabBarIOS in my app. I want to change the title of the current route when a tab selected.
the first way that didn't work
While creating NavigatorIOS, I user a variable at state object but updating state didn't change the title. (even though the render is called again)
onTabChanged: function (title) {
this.setState({
selectedTab: title,
});
},
render() {
return (
<NavigatorIOS
...
initialRoute={{
component: Tabs,
title: this.state.selectedTab,
passProps: {
onTabChanged: this.onTabChanged
}
}}
/>
);
},
the second way that didn't work
I also tried updating the state of the the NavigatorIOS which I referred as nav. There is a routeStack object in the state of the NavigatorIOS which keeps an array of the route items. So I updated the array via setState of the NavigatorIOS but it didn't work either.
the third way that didn't work
I tried to change the title from Objective C as Native Module but I couldn't reach to that specific navigation bar from the NSObject.
I hope someone can help.
I think you're supposed to be able to do this with navigator.replace but at the moment the replacement of the title seems to be broken:
https://github.com/facebook/react-native/issues/476
var route = this.props.navigator.navigationContext.currentRoute;
route.title = "newTitle";
route.rightButtonTitle = "newRightButtonTitle",
route.onRightButtonPress = () => {
;
};
this.props.navigator.replace(route);
BTW, you can also change tintColor of NavigatorIOS by following code...
var app = React.createClass({
getInitialState: function() {
return {
shadowHidden: false,
barTintColor: '#f04f46',
titleTextColor: '#fff',
tintColor: '#fff',
}
},
_navigator : function(navigatorProps){
this.setState(navigatorProps);
},
render: function(){
return <NavigatorIOS ref='nav' style={styles.container}
shadowHidden={this.state.shadowHidden}
barTintColor={this.state.barTintColor}
titleTextColor={this.state.titleTextColor}
tintColor={this.state.tintColor}
translucent={false}
initialRoute={{
title: title,
component: component,
passProps: Object.assign({
navigatorHook: this._navigator,
}, this.props),
}}
/>;
}
});
Now, in next Componet
this.props.navigatorHook({tintColor: 'red'});

Resources