The view is not rendering in iOS build but its running fine in Android,
the view is not navigating to the next view.
Here is the navigation structure, the screen not navigating from Address Result to AddressDetail
const StackNav = StackNavigator({
Main: {
screen: Addresssearch,
navigationOptions: ({ navigation }) => ({
title: "Address Search",
header: null
})
},
AddressDetail: {
screen: AddressDetails,
navigationOptions: (props) => ({
title: "Profile View",
})
},
AddressResult: {
screen: AddressResult,
navigationOptions: (props) => ({
title: "",
})
},{
headerMode: 'float'
})
The render Function of Address Detail class
render(){
console.log("=========== View Details Props ============");
const {bgImageTop, boxWithName, phoneIcon, showMapBtn, locationIcon, profile_icon} = images;
const { container, topCover, coverView, subContainer, info1, titleLabel, profileImage,subHeading } = styles;
const {data, differentSearchData} = this.state.dataArray;
const personData = data
const { firstname, lastname, middlename, age, streetAddress, city, zipcode, landline } = personData["0"];
const routeName = this.props.navigation.state.routeName
console.log("routeName: "+routeName)
const { onScroll = () => {} } = this.props;
return(
<View>
<Text>Read</Text>
</View>
);
}}
Here the console statement is executed but I can't see the screen navigating from Address Result to Address Details in iOS build
Details:
"react": "^16.0.0-alpha.12",
"react-native": "^0.48.3",
"react-navigation": "^1.0.0-beta.12",
Related
I am new to react native , and I am facing a problem with handling props and state ,when i am using redux, I get the data needed for rendering the flat list in the right form but some how the data property inside the flat list only see {this.props.customers} as undefined.
Here is my code:
componentWillMount() {
debugger;
this.props.getCustomers();
debugger;
}
componentDidUpdate(prevProps) {
if (prevProps.customers !== this.props.customers) {
this.props.getCustomers();
}
}
render = () => {
return (
<View>
<FlatList
data={this.props.customers}
renderItem={({ item }) =>
<View style={styles.GridViewContainer}>
<Text style={styles.GridViewTextLayout}>{item.name}</Text>
</View>}
keyExtractor={(x, index) => index}
numColumns={3}
/>
</View>
);
}
}
const mapStateToProps = (state) => {
const customers = state.customers;
console.log(customers);
debugger
return customers;
};
export default connect(mapStateToProps, {
getCustomers
})(CustomersList);
And the getCustomers action :
export const getCustomers = () => {
debugger;
return (dispatch) => {
dispatch(setCustomerLoading)
axios
.get('https://calm-sands-26165.herokuapp.com/api/customers')
.then(res =>
dispatch({
type: GET_CUSTOMERS,
payload: res.data,
})
)
.catch(err =>
dispatch({
type: GET_ERRORS,
payload: null
})
);
};
}
Thanx in advance.
In mapStateToProps you should return an object, not a value. Each entry in that object will be a prop for the component that's being connected to the store.
In your case, this should be the fix:
const mapStateToProps = (state) => {
const customers = state.customers;
return { customers };
};
I'm in the process of creating a social media app and I've the following diagram of screen transition:
Main -> Profile -> Followers -> John's Profile -> John's Followers ->
Emily's Profile -> ....
How can I implement a flow like this? Currently my router implementation is buggy, I can not go nested, it returns the previous screen.
Here is the part of the router to express my problem:
const appStack = createStackNavigator(
{
[PROFILE_STACK]: { screen: profileStack },
[PROFILE_FOLLOWERS_STACK]: { screen: profileFollowersStack },
[PROFILE_FOLLOWINGS_STACK]: { screen: profileFollowingsStack }
},
{
initialRouteName: PROFILE_STACK,
headerMode: "none"
}
);
const profileStack = createStackNavigator(
{
[PROFILE]: {
screen: UserProfileScreen,
navigationOptions: () => ({
header: null
})
}
},
{
initialRouteName: PROFILE
}
);
const profileFollowersStack = createStackNavigator(
{
[PROFILE_FOLLOWERS]: {
screen: UserFollowersScreen,
navigationOptions: () => ({
header: null
})
}
},
{
initialRouteName: PROFILE_FOLLOWERS
}
);
const profileFollowingsStack = createStackNavigator(
{
[PROFILE_FOLLOWINGS]: {
screen: UserFollowingsScreen,
navigationOptions: () => ({
header: null
})
}
},
{
initialRouteName: PROFILE_FOLLOWINGS
}
);
export const goUserProfile = function(navigation, userId) {
const { navigate } = navigation;
navigate(PROFILE_STACK, {
userId: userId
});
};
export const goUserFollowers = function(navigation, userId) {
const { push } = navigation;
push(PROFILE_FOLLOWERS_STACK, {
userId: userId
});
};
export const goUserFollowings = function(navigation, userId) {
const { push } = navigation;
push(PROFILE_FOLLOWINGS_STACK, {
userId: userId
});
};
The problem was I was using navigate() method in my goUserProfile(), not push(). After using push(), my problem is solved.
Reference:
React Navigation V2: Difference between navigation.push and navigation.navigate
When I specify drawerLockMode direactly with createStackNavigator it is not working.
const drawerStack = createStackNavigator({
HomeScreen: { screen: HomeScreen },
}, {
headerMode: 'screen',
navigationOptions: {
drawerLockMode:'locked-closed'
}
})
But when I use drawerStack variable to define navigationOptions, it is working.
drawerStack.navigationOptions = ({ navigation }) => {
drawerLockMode = 'locked-closed';
return {
drawerLockMode,
};
};
Am I doing any mistake when I am directly using it inside createStackNavigator?
Update
As #bennygenel suggested, we need to user drawerLockMode in drawerNavigator instead of stackNavigator. Here is what i have done.
const drawerNavigator = createDrawerNavigator({
drawerStack: drawerStack
}, {
contentComponent: DrawerComponent,
navigationOpions:{
drawerLockMode:'locked-closed'
}
})
But it is not working in this way also. The only way it is working is by using the const variable created using createStackNavigator or createDrawerNavigator
Try the following code, it's working for me:
const UserHome_StackNavigator = StackNavigator({
userHm: {
screen: UserHome,
navigationOptions: ({ navigation }) => ({
title: 'User screen title',
headerStyle: {
backgroundColor: 'white',
},
headerTintColor: 'black'
}),
},
});
UserHome_StackNavigator.navigationOptions = ({ navigation }) => {
let drawerLockMode = 'locked-closed';
//logic here to change conditionaly, if needed
return {
drawerLockMode,
};
};
in case someone need this:
const drawerNavigator = createDrawerNavigator({
drawerStack: drawerStack
}, {
contentComponent: DrawerComponent,
navigationOpions: ({navigation}) => {
let routeName = navigation.state.routes[navigation.state.routes.length-1].routeName;
if(['Animation', 'Splash', 'Intro', 'Login', 'Signup'].indexOf(routeName)>=0){
return {
drawerLockMode: 'locked-closed'
}
}
return {}
}
})
Here is the error I get when navigating to that screen. Note that the error happens on Android only, not on iOS (despite being generally related to malformed JSX).
Cannot add a child that doesn't have a YogaNode to a parent without a measure function! (Trying to add a 'ReactRawTextShadowNode' to a 'LayoutShadowNode')
Basically, here is my main TabNavigator, using the ContactScreen component as a screen (repo link):
const CustomTabs = TabNavigator({
Campaigns: {
screen: Campaigns,
navigationOptions: {
tabBarIcon: ({ tintColor }) => (<Icon name="mail" style={{ color: tintColor }} />)
}
},
Transactional: {
screen: MessagesList,
navigationOptions: {
tabBarIcon: ({ tintColor }) => (<Icon name="stats" style={{ color: tintColor }} />)
}
},
Contacts: {
screen: ContactsScreen,
navigationOptions: {
tabBarIcon: ({ tintColor }) => (<Icon name="contacts" style={{ color: tintColor }} />)
}
}
And here is the ContactsScreen component returning a StackNavigator, which is used as a screen inside the main TabNavigator (repo link):
const ListsNavigator = StackNavigator({
ContactLists: {
screen: ContactLists,
navigationOptions: {
header: 'none',
},
},
ContactList: {
screen: ContactList,
},
ListContacts: {
screen: ListContacts,
navigationOptions: ({ navigation }) => ({
title: `${navigation.state.params.name}`,
}),
},
},
{
initialRouteName: 'ContactLists'
}
)
export default class ContactsScreen extends React.Component {
render() {
return (
<ListsNavigator />
)
}
}
After investigating more, I found that the issue is due to a bug in react-navigation. More specifically, it's not possible to use a StackNavigator with the header field of navigationOptions set to 'none'. I filed an issue on the repo: https://github.com/react-navigation/react-navigation/issues/4081
I am following a tutorial for react-native, however they are doing it for IOS, there is one part where they use AlertIOS.prompt like this
AlertIOS.prompt(
'Add New Item',
null,
[
{text: 'Cancel', onPress: () => console.log('Cancel Pressed'), style: 'cancel'},
{
text: 'Add',
onPress: (text) => {
this.itemsRef.push({ title: text })
}
},
],
'plain-text'
);
I am trying to remake this for android but cannot get it working, I did find this https://www.npmjs.com/package/react-native-prompt
import Prompt from 'react-native-prompt';
<Prompt
title="Say something"
placeholder="Start typing"
defaultValue="Hello"
visible={ this.state.promptVisible }
onCancel={ () => this.setState({
promptVisible: false,
message: "You cancelled"
}) }
onSubmit={ (value) => this.setState({
promptVisible: false,
message: `You said "${value}"`
}) }/>
However I cannot get this to work either, It is supposed to display the prompt when I press a button but nothing happens..
Here is the full original code with AlertIOS
'use strict';
import React, {Component} from 'react';
import ReactNative from 'react-native';
const firebase = require('firebase');
const StatusBar = require('./components/StatusBar');
const ActionButton = require('./components/ActionButton');
const ListItem = require('./components/ListItem');
const styles = require('./styles.js')
const {
AppRegistry,
ListView,
StyleSheet,
Text,
View,
TouchableHighlight,
AlertIOS,
} = ReactNative;
// Initialize Firebase
const firebaseConfig = {
apiKey: "AIzaSyA9y6Kv10CAl-QOnSkMehOyCUejwvKZ91E",
authDomain: "dontforget.firebaseapp.com",
databaseURL: "https://dontforget-bd066.firebaseio.com",
storageBucket: "dontforget-bd066.appspot.com",
};
const firebaseApp = firebase.initializeApp(firebaseConfig);
class dontforget extends Component {
constructor(props) {
super(props);
this.state = {
dataSource: new ListView.DataSource({
rowHasChanged: (row1, row2) => row1 !== row2,
})
};
this.itemsRef = this.getRef().child('items');
}
getRef() {
return firebaseApp.database().ref();
}
listenForItems(itemsRef) {
itemsRef.on('value', (snap) => {
// get children as an array
var items = [];
snap.forEach((child) => {
items.push({
title: child.val().title,
_key: child.key
});
});
this.setState({
dataSource: this.state.dataSource.cloneWithRows(items)
});
});
}
componentDidMount() {
this.listenForItems(this.itemsRef);
}
render() {
return (
<View style={styles.container}>
<StatusBar title="Grocery List" />
<ListView
dataSource={this.state.dataSource}
renderRow={this._renderItem.bind(this)}
enableEmptySections={true}
style={styles.listview}/>
<ActionButton onPress={this._addItem.bind(this)} title="Add" />
</View>
)
}
_addItem() {
AlertIOS.prompt(
'Add New Item',
null,
[
{text: 'Cancel', onPress: () => console.log('Cancel Pressed'), style: 'cancel'},
{
text: 'Add',
onPress: (text) => {
this.itemsRef.push({ title: text })
}
},
],
'plain-text'
);
}
_renderItem(item) {
const onPress = () => {
AlertIOS.alert(
'Complete',
null,
[
{text: 'Complete', onPress: (text) => this.itemsRef.child(item._key).remove()},
{text: 'Cancel', onPress: (text) => console.log('Cancelled')}
]
);
};
return (
<ListItem item={item} onPress={onPress} />
);
}
}
AppRegistry.registerComponent('dontforget', () => dontforget);
Could anyone tell me how I could make this work for android?
I think you can use the following libraries : https://github.com/mmazzarolo/react-native-dialog
Example code to get user input are as follows (not in docs)
<Dialog.Container visible={true}>
<Dialog.Title>Account delete</Dialog.Title>
<Dialog.Description>
Do you want to delete this account? You cannot undo this action.
</Dialog.Description>
<Dialog.Input label="Cancel" onChangeText={(text) => this.setState({username : text})} />
<Dialog.Button label="Delete" onPress={() => {
console.log(this.state.username);
this.setState({promptUser : false});
}} />
</Dialog.Container>
These looks like a good alternative since its natively implemented
https://github.com/shimohq/react-native-prompt-android
Actually, you can use a cross-platform prompt component that works fine both on Android and Ios. The link is given below.
https://www.npmjs.com/package/react-native-prompt-crossplatform and its
repository
link is
https://github.com/Ramiah-Viknesh/react-native-prompt-crossplatform
I developed a small utility to solve this issue. It might be useful.
https://github.com/eleviven/react-native-alertbox