0

function DateTimePick is a child function to render picked date and picked time in parent component Reservation. Currently there are two issues with the codes: 1. the form in Reservation does not reset after submit data. 2. child DateTimePick fails to update the state for 'date' and 'time' in parent Reservation. Please have a look and lemme know how to fix these. Thanks.

child function DateTimePick is below:

import React, {useState} from 'react';
import {View, Button, Platform, Text, TextInput, StyleSheet} from 'react-native';
import DateTimePicker from '@react-native-community/datetimepicker';
import { Icon } from 'react-native-elements';
import Moment from "moment";

export const DateTimePick = () => {  
  
  const [date, setDate] = useState(new Date());
  const [mode, setMode] = useState('date');
  const [show, setShow] = useState(false);
  
  const onChange = (event, selectedDate) => {
      const currentDate = selectedDate || date;
      setShow(Platform.OS === 'ios');
      setDate(currentDate);
  };
  
  const showMode = (currentMode) => {
      setShow(true);
      setMode(currentMode);
  };
  
  const showDatepicker = () => {
      showMode('date');
  };
  
  const showTimepicker = () => {
      showMode('time');
  };
    
      return (
      <View>                
          <View style={styles.formRow}>
              <Text style={styles.formLabel}> Date</Text>
              <Text onPress={showDatepicker} style={styles.formItem} value_date={date.toDateString()} onChange = {(value_date) => this.props.setState({date: value_date})}><Icon type='font-awesome-5' name='calendar' color='#512DA8' />{' ' + Moment(date).format('DD-MMM-YYYY') }</Text>
          </View>
          <View style={styles.formRow}>
              <Text style={styles.formLabel}> Time</Text>
              <Text onPress={showTimepicker} style={styles.formItem} value_time={date.toTimeString()} onChange = {(value_time) => this.props.setState({time: value_time})}><Icon type='font-awesome-5' name='clock' color='#512DA8' /> {' ' + Moment(date).format('h:mm A') }</Text>
          </View>
          {show && (
          <DateTimePicker
              testID="dateTimePicker"
              value={date}
              mode={mode}
              is24Hour={true}
              display="default"
              onChange={onChange}
          />
          )}        
      </View>
      );
  };

//export default DateTimePick;

const styles = StyleSheet.create({
  formRow: {
      alignItems: 'center',
      justifyContent: 'center',
      flex: 1,
      flexDirection: 'row',
      margin: 20
  },
  formLabel: {
      fontSize: 18,
      flex: 1
  },
  formItem: {
      flex: 1        
  },
  modal: {
      justifyContent: 'center',
      margin: 20
  },
  modalTitle: {
      fontSize: 24,
      fontWeight: 'bold',
      backgroundColor: '#512DA8',
      textAlign: 'center',
      color: 'white',
      marginBottom: 20
  },
  modalText: {
      fontSize: 18,
      margin: 10
  },
})

parent Reservation which produces a reservation form and a reservation input confirmed modal

import React, {Component} from 'react';
import { Text, View, ScrollView, StyleSheet, Switch, Button, TextInput, Modal} from 'react-native';
import {DateTimePick} from './DateTimePickComponent';

class Reservation extends Component {
    constructor(props) {
        super(props);
        this.state = {
            guests: 1,
            smoking: false,
            notes:'',
            date: new Date().toDateString(),
            time: new Date().toTimeString(),
            showModal: false          
        }
    }

    toggleModal() {
        this.setState({showModal: !this.state.showModal})
    }

    handleReservation() {
        console.log(JSON.stringify(this.state));  //log current state
        //this.setState({                           // reset the form  
        //})
        this.toggleModal();
    }

    resetForm() {
        this.setState({
            guests: 1,
            smoking: false,
            notes:'',
            date: new Date().toDateString(),
            time: new Date().toTimeString(),
            showModal: false 
        });
    }

    
    render() {
            //, transform: [{ scaleX: 3 }, { scaleY: 1.5 }]   => for switch
        return(
            <ScrollView>
                <View style={styles.formRow}>
                    <Text style={styles.formLabel}> Guests </Text>
                    <TextInput style={styles.formItem} keyboardType="numeric" placeholder="Number" 
                        value_guests={this.state.guests}
                        onChangeText = {(value_guests) => this.setState({guests: value_guests})} >                                                   
                    </TextInput>
                </View>

                <View style={styles.formRow}>
                    <Text style={styles.formLabel}> Notes </Text>
                    <TextInput style={styles.formItem} keyboardType="default" placeholder="Allergy,..etc"  
                      value_notes={this.state.notes}
                      onChangeText = {(value_notes) => this.setState({notes: value_notes})} >                             
                    </TextInput>
                </View>                
                <View style={styles.formRow}>                     
                    <Text style={styles.formLabel}> Non-Smoking </Text>                   
                    <Switch style={{ flex: 1, backgroundColor: "orange", paddingLeft:0, marginLeft:0 }} trackColor={{true: 'red', false: 'grey'}}
                    value={this.state.smoking} 
                    onValueChange = {(value) => this.setState({smoking: value})} />
                    <Text style={styles.formLabel}> Smoking </Text>                    
                </View>
                                          
                <DateTimePick />

                <View style={styles.formRow}>
                    <Button
                        onPress={() => this.handleReservation()}
                        title="Reserve"
                        color="#512DA8"
                        accessibilityLabel="Learn more about this purple button"
                        />
                </View>

                <Modal animationType={'slide'} transparent={false} visible={this.state.showModal}
                onDismiss={() => {this.toggleModal()}}
                onRequestClose={() => {this.toggleModal()}}>
                    <View style={styles.modal}>
                        <Text style={styles.modalTitle}>Your Reservation</Text>
                        <Text style={styles.modalText}>Number of Guests: {this.state.guests}</Text>
                        <Text style={styles.modalText}>Notes: {this.state.notes}</Text>
                        <Text style = {styles.modalText}>Smoking?: {this.state.smoking ? 'Yes' : 'No'}</Text>
                        <Text style = {styles.modalText}>Date and Time: {this.state.date} {this.state.time}</Text>
                        <Button 
                            onPress = {() =>{this.toggleModal(); this.resetForm();}}
                            color="#512DA8"
                            title="Close" 
                            />
                    </View>

                </Modal>
            </ScrollView>
        );
    }
}

const styles = StyleSheet.create({
    formRow: {
        alignItems: 'center',
        justifyContent: 'center',
        flex: 1,
        flexDirection: 'row',
        margin: 20
    },
    formLabel: {
        fontSize: 18,
        flex: 1
    },
    formItem: {
        flex: 1        
    },
    modal: {
        justifyContent: 'center',
        margin: 20
    },
    modalTitle: {
        fontSize: 24,
        fontWeight: 'bold',
        backgroundColor: '#512DA8',
        textAlign: 'center',
        color: 'white',
        marginBottom: 20
    },
    modalText: {
        fontSize: 18,
        margin: 10
    },
})

export default Reservation;
hang-coder
  • 420
  • 4
  • 8

2 Answers2

1

you could fix it by transfering state consts date, show, mode to parent Reservation

then pass state change functions to the DateTimePick component in props like below

<DateTimePick onDateChange={(date) => this.setState({date: date}) } />

and in DateTimePick component:

 const onChange = (event, selectedDate) => {
      const currentDate = selectedDate || date;
      setShow(Platform.OS === 'ios');
      props.onDateChange(currentDate);
  };

also dont forget to pass props in the component like

export const DateTimePick = (props) => { 
Václav Ryska
  • 215
  • 2
  • 7
  • The DateTimePick was moved out of the parent to make it better for my eyes :) and it works well by its own so I prefer not merging it back. I look for a way to use data from child to update state for parent like this post https://chafikgharbi.com/react-update-parent-child-state/ but not yet worked it out ... Appreciate a similar solution. The other issue is the form does not reset. Lemme know if you can help. Thanks – hang-coder Apr 14 '21 at 08:52
  • I think this solution is a good one, and the link that you shared pretty much do the same. He doesn't ask you to merge both components back together, just put the state on parent component and pass the `onChange` handlers to the `DateTimePick` – jted95 Apr 14 '21 at 12:40
  • @garjted If using one component means bring half of its code over then it will be a pain. The link I shared stays away from this pain and is the right approach but the code there is too coarse to be useful for real project implementation. These two links are way better: https://stackoverflow.com/questions/35537229/how-to-update-parents-state-in-react, http://plnkr.co/edit/tGWecotmktae8zjS5yEr?p=preview&preview – hang-coder Apr 15 '21 at 04:14
0

Solved it. For using child data to update parents' state need to pass a handler for setting the state of parent to child, refer How to update parent's state in React?

class Parent extends React.Component {
  constructor(props) {
    super(props)

    this.handler = this.handler.bind(this)
  }

  handler() {
    this.setState({
      someVar: 'some value'
    })
  }

  render() {
    return <Child handler = {this.handler} />
  }
}

class Child extends React.Component {
  render() {
    return <Button onClick = {this.props.handler}/ >
  }
}

In implementation, a handler is inserted into parent class Reservation as below

...
class Reservation extends Component {
    constructor(props) {
...
this.handler = this.handler.bind(this) 
    }

    handler(selectedDate) {
        this.setState({
            date: Moment(selectedDate).format('DD-MMM-YYYY'),
            time: Moment(selectedDate).format('h:mm A'), 
        })
      }
...

In child DateTimePick, embed the handler in onChange to pass child update from onChange to state update in parent Reservation like this

...

export const DateTimePick = (props) => {
    const handler = props.handler;
    ...

    const onChange = (event, selectedDate) => {
        ...
        handler(currentDate);
    };
...
...
hang-coder
  • 420
  • 4
  • 8