I have a row where date is getting displayed on click of that view, I want a datepicker to pop up and display.
class EditProfilePicture extends React.Component {
state = {
currentDate: new Date()
};
setCurrentDateForIOS = currentDate => {
this.setState({ currentDate });
};
pickDate = () => (
<View>
{Platform.OS === "ios" ? (
<DatePickerForIOS
setCurrentDateForIOS={this.setCurrentDateForIOS}
/>
) : (
DatePickerForAndroid().then(currentDate =>
this.props.changeBirthDate({ currentDate })
)
)}
</View>
);
render() {
return (
<View>
<View style={styles.Container}>
<Text style={styles.heading}>Your birthday</Text>
<TouchableWithoutFeedback onPress={this.pickDate}>
<View style={styles.dropdown}>
<Text style={styles.textStyle}>
{DateFormatter(this.state.currentDate)}
</Text>
<Icon name="chevron-down" color={MED_GREY} />
</View>
</TouchableWithoutFeedback>
</View>
</View>
);
}
}
And in DatePickerForIOS I have this---
import React from "react";
import PropTypes from "prop-types";
import { DatePickerIOS } from "react-native";
const DatePickerForIOS = props => {
return (
<DatePickerIOS
date={new Date()}
mode="date"
onDateChange={() => props.setCurrentDateForIOS}
/>
);
};
DatePickerIOS.propTypes = {
setCurrentDateForIOS: PropTypes.func.isRequired
};
export default DatePickerForIOS;
While the code works fine for android, in IOS the screen contains NAN/NAN/NAN as text initially and the datepicker doesn't open up when clicked on the view.
DatePickerIOS needs to be part of the render function of EditProfilePicture
Currently you create the component fromonPress from TouchableWithoutFeedback.
You would need to do something like the docs say
render() {
return (
<View style={styles.container}>
<DatePickerIOS
date={this.state.chosenDate}
onDateChange={this.setDate}
/>
</View>
)
}
You would need to hide/show this a state boolean value to toggle on off.
Without knowing your Android code, I suspect that is acting like a popup modal.
Another solution would be to use a package like react-native-modal-datetime-picker which has the same interface between iOS and Android
Related
I have the ff stacknavigation on my App.js:
<NavigationContainer>
<Stack.Navigator
initialRouteName={'BookListing'}>
<Stack.Screen name="Book List" component={Tabs} />
<Stack.Screen
name="BookDetailScreen"
component={BookDetail}
/>
</Stack.Navigator>
</NavigationContainer>
Now on my BookList Screen file, I created an onPressHandler function so I can navigate on the details screen and probably pass the data from redux state.
class BookListingScreen extends Component {
componentDidMount() {
this.props.fetchBooks();
}
onPressHandler = () => {
this.props.navigation.navigate('BookDetailScreen');
};
render() {
let content = (
<BookList
onPress={this.onPressHandler}
books={this.props.randomBooks.books}
/>
);
if (this.props.randomBooks.isFetching) {
content = <ActivityIndicator size="large" />;
}
return (
<View style={styles.container}>
<View>{renderHeader()}</View>
<View>{content}</View>
</View>
);
}
}
Here's my book list component:
export default class BookList extends Component {
_keyExtractor = item => item.cover_i;
render() {
return (
<FlatList
style={{flex: 1}}
data={this.props.books}
keyExtractor={this._keyExtractor}
renderItem={({item} = this.props.books) => {
return (
<BookItem onPressHandler={this.props.onPressHandler} item={item} />
);
}}
/>
);
}
}
Now on my item list, I am trying to use a TouchableOpacity to go the Details Screen.
export default class BookItem extends Component {
render() {
const {title, author_name, oclc = []} = this.props.item;
const onPressHandler = this.props.onPressHandler;
return (
<TouchableOpacity onPress={() => onPressHandler}>
<View style={styles.cardContainerStyle}>
<View style={{paddingRight: 5}}>
<Text style={styles.cardTextStyle}>{title}</Text>
</View>
</View>
</TouchableOpacity>
);
}
}
However, this doesn't go to the Details Screen. Any idea what's happening here?
change this in BookItem
onPress={() => onPressHandler}
to this
onPress={() => onPressHandler()}
or
onPress={onPressHandler}
I'm new to React Native and I'm trying to create an app with a custom navbar, that jumps between pages when you click links.
Here is an abbreviated version of my code:
class App extends Component {
constructor(props) {
super(props);
this.state = {
dicePage: true,
itemsPage: false
}
}
dicePress = () => {
this.setState({
dicePage: true,
itemsPage: false
})
}
itemsPress = () => {
this.setState({
dicePage: false,
itemsPage: true
})
}
render() {
return (
<View style={styles.container}>
<ImageBackground source={backgroundTile} style={styles.bgImage}>
<View style={styles.content}>
<View style={styles.logoContainer}>
<Image source={require('./assets/images/Logo.png')} style={styles.logo} />
</View>
{this.state.dicePage && <DicePage />}
{this.state.itemsPage && <ItemsPage />}
<NavBar value='Dice' dicePress={this.dicePress} itemsPress={this.itemsPress} />
</View>
</ImageBackground>
</View>
);
}
}
export default App;
and
class NavBar extends Component {
constructor(props) {
super(props);
}
render() {
return (
<View style={styles.bottomNav}>
<TouchableOpacity onPress={this.props.dicePress}>
<Text key='dice' style={styles.nav}>Dice</Text>
</TouchableOpacity>
<TouchableOpacity onPress={this.props.itemsPress}>
<Text key='items' style={styles.nav}>Items</Text>
</TouchableOpacity>
</View>
)
}
}
export default NavBar;
So this works when I test the app - and I'm going to have 4 or 5 pages, so want more options than a ternary operator etc. - but I think there's probably a better or more elegant way to do this.
I've tried React Navigator and other things but am really looking for the absolute simplest way to achieve this (hopefully with DRY coding, as the repetition feels wrong to me). Should I be mapping links and functions for this? I don't think I've ever mapped functions before and realise that there probably should be a single adaptable function that would work for all.
Thanks for any advice!
First Approach
You could make a pages object where each key is an identifier for a page and where each corresponding value is the component that represents a page:
const pages = {
dicePage: DicePage,
itemsPage: ItemsPage
};
This way we can decide what should be rendered based on the key only, and all navigation can links can share the same onPress handler.
App.js
class App extends Component {
constructor(props) {
super(props);
this.state = {
currentPage: "dicePage" // Default page
};
}
pagePress = (pageName) => {
this.setState({ currentPage: pageName });
};
render() {
const Page = pages[this.state.currentPage]; // What page should be rendered (based on the `currentPage` key)
return (
<View>
<View>
<Page />
<NavBar value="Dice" pagePress={this.pagePress} />
</View>
</View>
);
}
}
Navbar.js
class NavBar extends Component {
render() {
return (
<View>
<TouchableOpacity onPress={() => this.props.pagePress("dicePage")}>
<Text key="dice">Dice</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => this.props.pagePress("itemsPage")}>
<Text key="items">Items</Text>
</TouchableOpacity>
</View>
);
}
}
So if you want to expand this with more pages you only need to add key value pairs to the pages object and links to your Navbar.
I've removed some things like styling and images to simplify the example.
Second Approach
const pages = [
{ key: "dicePage", page: DicePage, pageLinkName: "Dice" },
{ key: "itemsPage", page: ItemsPage, pageLinkName: "Items" },
];
class NavBar extends Component {
render() {
return (
<View>
{pages.map((page) => {
return (
<TouchableOpacity
onPress={() => this.props.pagePress(page.key)}
key={page.key}
>
<Text>{page.pageLinkName}</Text>
</TouchableOpacity>
);
})}
</View>
);
}
}
class App extends Component {
constructor(props) {
super(props);
this.state = {
currentPage: "dicePage", // Default page
};
}
pagePress = (pageName) => {
this.setState({ currentPage: pageName });
};
render() {
const Page = pages.filter((page) => page.key === this.state.currentPage)[0]
.page;
return (
<View>
<View>
<Page />
<NavBar value="Dice" pagePress={this.pagePress} />
</View>
</View>
);
}
}
Largely the same approach, but structure of pages has changed where you now also don't need to manually add new links, but you only need to add new objects to pages, which is now an array.
I'm trying to create my first App using React-Native,
i've created a class which renders the authentication form, after handling the submit the App should render the Navigation Screen with its tabs. I think i can "refresh" in someway the App class rendering from the Authentication Screen so it can check again if the user has authenticated or not, but i'm not really sure
App.Js:
import AuthScreen from './screens/AuthScreen';
export default class App extends React.Component {
state = {
isLoadingComplete: false,
isAuthenticated: false,
};
render() {
if (!this.state.isLoadingComplete && !this.props.skipLoadingScreen) {
return (
<AppLoading
startAsync={this._loadResourcesAsync}
onError={this._handleLoadingError}
onFinish={this._handleFinishLoading}
/>
);
} else {
if(this.state.isAuthenticated == true) {
return (
<View style={styles.container}>
<StatusBar hidden = {true} />
<AppNavigator />
</View>
);
} else {
return (
<View style={styles.container}>
<StatusBar hidden = {true} />
<AuthScreen />
</View>
);
}
}
}
AuthScreen.js:
export default class AuthScreen extends Component {
handleSubmit = () => {
const value = this._form.getValue();
console.log('value: ', value);
}
render() {
return (
<View style={styles.container}>
<View style={styles.auth_container}>
<Form
ref={c => this._form = c}
type={User}
options={options}
/>
<Button
title="Submit"
onPress={this.handleSubmit}
/>
</View>
</View>
);
}
}
You can do this by using react-navigation(RN navigation library). But per code in question your trying to toggle between screen.
In your way: handleSubmit method of AuthScreen if success to following
handleSubmit = () => {
check auth logic
this.props.onSuccessFullLogin(value)
}
Update State in ParentComponent to toggle between screens App Component:
<AuthScreen /> this should be like <AuthScreen onSuccessFullLogin={()=>this.setState({isAuthenticated:true})} />
I have created a component called OrderGuideSelect and I am trying to render it in another area of our app. The problem is the OrderGuideSelect component is not rendering. When I set up breakpoints I am able to hit inside of the renderOrderGuideOptions function but it never makes it into the OrderGuideSelect.js file. I also tried putting 'export default' in front of the class declaration instead of the connection but it didn't make a difference. Does anyone know how to get the OrderGuideSelect component rendering properly?
Here is where I call the function that renders the OrderGuideSelect component:
<TouchableOpacity onPress={() => this.renderOrderGuideOptions()}>
<MBIcon name="ico-24-filter" size={30} style={styles.filterIcon}/>
</TouchableOpacity>
And here is the rendering function:
renderOrderGuideOptions = () => {
return (
<View>
<OrderGuideSelect />
</View>
)
}
Here is the OrderGuideSelect.js file:
import React, {Component} from 'react';
import {View, FlatList, ActivityIndicator, StyleSheet} from 'react-native';
import {connect} from 'react-redux';
import {fetchOrderGuides} from '../../actions/AppActions';
import {orderGuideSelected} from '../../actions/ProductAction';
import Header from '../../components/Header/Header';
import {createIconSetFromIcoMoon} from 'react-native-vector-icons';
import selection from '../../selection';
import OrderGuideOption from './OrderGuideOption';
const MBIcon = createIconSetFromIcoMoon(selection);
class OrderGuideSelect extends Component {
constructor(props) {
super(props);
}
componentWillMount() {
this.props.dispatch(fetchOrderGuides());
}
selectOrderGuide = id => {
this.props.dispatch(orderGuideSelected(id));
}
render() {
const {isLoading, orderGuides} = this.props.orderGuide;
return (
<View style={styles.wrapper}>
<Header />
<View style={styles.iconLine}>
<MBIcon name='ico-24-filter' style={styles.filterIcon} />
</View>
{isLoading &&
<ActivityIndicator
style={{alignSelf: 'center'}}
animating={true}
size='large'
/>
}
{!isLoading &&
<View style={styles.optionList}>
<FlatList
style={styles.optionList}
data={orderGuides}
keyExtractor={(item, index) => item.id.toString()}
renderItem={({item}) => <OrderGuideOption guideData={item} isSelected={item.id == this.props.selectedGuide.id} onSelected={this.selectOrderGuide} />}
/>
</View>
}
</View>
);
}
}
function mapStateToProps(state){
const {products, orderGuide} = state;
return {
selectedGuide: products.selectedOrderGuide,
orderGuide
}
}
export default connect(mapStateToProps)(OrderGuideSelect);
Also, I may be importing of the OrderGuideSelect component should be correct:
In your code calling this.renderOrderGuideOptions function on onPress event doesn't make sense, i.e. this.renderOrderGuideOptions returns the element but where to append it in DOM?
This should be achived using state in React. So you can set the state in onPress handler then use that state in render to show your OrderGuideOptions component.
So on onPress event bind the function handler:
<TouchableOpacity onPress={this.showOrderGuideOptions}>
<MBIcon name="ico-24-filter" size={30} style={styles.filterIcon}/>
</TouchableOpacity>
Now this showOrderGuideOptions will set the state named showOrderGuideFunction to true.
showOrderGuideOptions(){
this.setState({showOrderGuideFunction: true});
}
At last step use this showOrderGuideFunction state to render your component in the render function like this:
render() {
return (
<div>
...
{
this.state.showOrderGuideFunction &&
renderOrderGuideOptions()
}
</div>
)
}
You can do what you want probably holding a state property in your component and show your OrderGuideOptions according to this state property.
state = { showOrderGuideOptions: false };
renderOrderGuideOptions = () =>
this.setState( prevState => ( { showOrderGuideOptions: !prevState.showOrderGuideOptions }) );
render() {
return (
<View>
<TouchableOpacity onPress={this.renderOrderGuideOptions}>
<MBIcon name="ico-24-filter" size={30} style={styles.filterIcon}/>
</TouchableOpacity>
{ this.state.showOrderGuideOptions && <OrderGuideSelect /> }
</View>
)
}
I think you wanted to something similar to this
class RenderOrderGuideSelectComponent extends Component {
constructor(props) {
super(props);
this.state={
showOrderGuideSelect : false
};
}
renderOrderGuideOptions = () => {
this.setState({showOrderGuideSelect: true});
}
render() {
if(this.state.showOrderGuideSelect) {
return (
);
} else {
return (
this.renderOrderGuideOptions()}>
);
}
}
}
import React, { Component } from 'react';
import { AppRegistry, Text, View, TouchableOpacity } from 'react-native';
class Check extends Component {
constructor(props){
super(props);
this.pressed = true
}
_callme = () => {
if(!this.pressed){
return ( <View>
<TouchableOpacity onPress={this._callMe}>
Show me TextBox
</TouchableOpacity>
</View>
)
}
else{
return (
<View>
<TextInput />
</View>)
}
}
showText = () => {
return (
<TouchableOpacity on Press={this._callMe}>
<Text>Show me TextBox</Text>
</TouchableOpacity>
)
}
render() {
return(
<View>
{this.pressed ? this._callMe : this.showText}
</View>
)
}
}
AppRegistry.registerComponent('Check', () => Check);
I am Newbie into the ReactNative, what I want is when ever a user clicks on a button user should get a popup box for comment, but I don't know where I am doing wrong?
Since you want to render the returned value, you need to call the function with ()
{this.pressed ? this._callMe() : this.showText()}
Also showText function return component <TouchableOpacity on Press={this._callMe}> has a space between on Press change to onPress.