Billy Ronaldo Chandra
Billy Ronaldo Chandra

Reputation: 182

Clear state on custom component

Hey there I'm still learning with React Native and I have this custom picker component for iOS, and what I'm going to do is I want to clear the picker when I do onSubmit(). What should I do to set the picker state to its default state when I do onSubmit() from another component

PickerWrapper.js

class PickerWrapper extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            type_absen: this.props.items[0].description,
            modal: false
        }
    }

    render() {
        let picker;

        let iosPickerModal = (
            <Modal isVisible={this.state.modal} hideModalContentWhileAnimating={true} backdropColor={color.white} backdropOpacity={0.9} animationIn="zoomInDown" animationOut="zoomOutUp" animationInTiming={200} animationOutTiming={200} onBackButtonPress={() => this.setState({ modal: false })} onBackdropPress={() => this.setState({ modal: false })} >
                <View style={{ backgroundColor: color.white, width: 0.9 * windowWidth(), height: 0.3 * windowHeight(), justifyContent: 'center' }}>
                    <Picker
                        selectedValue={this.state.type_absen}
                        onValueChange={(itemValue, itemIndex) => {
                            this.setState({ type_absen: itemValue });
                            this.setState({ modal: false });
                            setTimeout(() => this.props.onSelect(itemValue), 1200);
                        }}
                    >
                        {this.props.items.map((item, key) => <Picker.Item label={item.description} value={item.id} key={item.id} />)}
                    </Picker>
                </View>
            </Modal>);

        if (Platform.OS === 'ios') {
            var idx = this.props.items.findIndex(item => item.id === this.state.type_absen);
            return (
                <View style={this.props.style}>
                    {iosPickerModal}
                    <TouchableOpacity onPress={() => this.setState({ modal: true })}>
                        <View style={{ flexDirection: 'row', height: this.props.height ? this.props.height : normalize(40), width: this.props.width ? this.props.width : 0.68 * windowWidth(), borderWidth: 1, borderColor: color.blue, alignItems: 'center', borderRadius: 5 }}>
                            <Text style={{ fontSize: fontSize.regular, marginRight: 30 }}> {idx !== -1 ? this.props.items[idx].description : this.state.type_absen}</Text>
                            <IconWrapper name='md-arrow-dropdown' type='ionicon' color={color.light_grey} size={20} onPress={() => this.setState({ modal: true })} style={{ position: 'absolute', right: 10 }} />
                        </View>
                    </TouchableOpacity>
                </View >);
        }
    }
   }

This is where I called my picker

App.js

class App extends Component {

  constructor() {
    super();
    this.state = {
      type_absen: ''
    }

    this.onSubmit = this.onSubmit.bind(this);
  }

onSubmit() {
  this.props.actionsAuth.changeSchedule(this.props.token, this.state.type_absen, (message) => alert(message));
  this.setState({ type_absen: ''}); 
 }
  
render(){
  let scheduleTypes = this.props.schedules;
  return(
      <PickerWrapper items={[{ "description": "Schedule Type", "id": "0" }, ...scheduleTypes]} onSelect={(item) => this.setState({ type_absen: item })} />
    );
  }
}

Upvotes: 1

Views: 342

Answers (1)

TBouder
TBouder

Reputation: 2719

To update the child (PickerWrapper) from the parent, you have to create a new method in the child and call it from the parent.
For this, the parent should have the child reference to have the ability to call some method from it

    class App extends Component {

      constructor() {
        super();
        this.state = {
          type_absen: ''
        }

        this.pickerRef = undefined;
        this.onSubmit = this.onSubmit.bind(this);
      }

    onSubmit() {
      this.props.actionsAuth.changeSchedule(this.props.token, this.state.type_absen, (message) => alert(message));
      this.setState({ type_absen: ''});
      this.pickerRef.reset();
     }

    render(){
      let scheduleTypes = this.props.schedules;
      return(
          <PickerWrapper
              ref={ref => ref && this.pickerRef = ref}
              items={[{ "description": "Schedule Type", "id": "0" }, ...scheduleTypes]}
              onSelect={(item) => this.setState({ type_absen: item })} />
        );
      }
    }

And then, create the reset method in the child :

class PickerWrapper extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            type_absen: this.props.items[0].description,
            modal: false
        }
    }

    reset = () => {
        this.setState({type_absen: this.props.items[0].description, modal: false})
    }

    render() {
        let picker;

        let iosPickerModal = (
            <Modal isVisible={this.state.modal} hideModalContentWhileAnimating={true} backdropColor={color.white} backdropOpacity={0.9} animationIn="zoomInDown" animationOut="zoomOutUp" animationInTiming={200} animationOutTiming={200} onBackButtonPress={() => this.setState({ modal: false })} onBackdropPress={() => this.setState({ modal: false })} >
                <View style={{ backgroundColor: color.white, width: 0.9 * windowWidth(), height: 0.3 * windowHeight(), justifyContent: 'center' }}>
                    <Picker
                        selectedValue={this.state.type_absen}
                        onValueChange={(itemValue, itemIndex) => {
                            this.setState({ type_absen: itemValue });
                            this.setState({ modal: false });
                            setTimeout(() => this.props.onSelect(itemValue), 1200);
                        }}
                    >
                        {this.props.items.map((item, key) => <Picker.Item label={item.description} value={item.id} key={item.id} />)}
                    </Picker>
                </View>
            </Modal>);

        if (Platform.OS === 'ios') {
            var idx = this.props.items.findIndex(item => item.id === this.state.type_absen);
            return (
                <View style={this.props.style}>
                    {iosPickerModal}
                    <TouchableOpacity onPress={() => this.setState({ modal: true })}>
                        <View style={{ flexDirection: 'row', height: this.props.height ? this.props.height : normalize(40), width: this.props.width ? this.props.width : 0.68 * windowWidth(), borderWidth: 1, borderColor: color.blue, alignItems: 'center', borderRadius: 5 }}>
                            <Text style={{ fontSize: fontSize.regular, marginRight: 30 }}> {idx !== -1 ? this.props.items[idx].description : this.state.type_absen}</Text>
                            <IconWrapper name='md-arrow-dropdown' type='ionicon' color={color.light_grey} size={20} onPress={() => this.setState({ modal: true })} style={{ position: 'absolute', right: 10 }} />
                        </View>
                    </TouchableOpacity>
                </View >);
        }
    }
   }

Additionnaly, your component is re-render each time a setState is set. You can avoid double re-render by switching

this.setState({type_absen: itemValue});
this.setState({modal: false});

to this

this.setState({type_absen: itemValue, modal: false});

Upvotes: 2

Related Questions