jefelewis
jefelewis

Reputation: 2049

React Hooks: Passing Hook State back to Parent Component

I'm in the process of building my first React Native library, but it's coming along with some issues of course. It's a small picker component library (date, time, datetime, list, states) for React Native, but I'm need some guidance as to how to do the next step.

App.js (Will Eventually be a NPM package, but using App for test)

I want to use the onValueChange so a user can use setState to set the state to their screen when importing the component from the NPM package. As of right now, it's just logging the value to the console (but the value isn't being passed correctly, so that doesn't work). That's why I have onValueChange as a ListPicker component prop. My question is further explained in the ListPicker.js description.

// Imports: Dependencies
import React, { useState, useEffect } from 'react';

// Imports: Components
import { ListPicker } from './src/ListPicker';

// React Native App
export default App = () => {

  // Test Data
  const items = [
    { label: '1', value: '1' },
    { label: '2', value: '2' },
    { label: '3', value: '3' },
    { label: '4', value: '4' },
    { label: '5', value: '5' },
    { label: '6', value: '6' },
    { label: '7', value: '7' },
    { label: '8', value: '8' },
    { label: '9', value: '9' },
    { label: '10', value: '10' }
  ];

  return (    
    <ListPicker listName="List Test" items={items} onValueChange={(value) => console.log(`Value Updated: ${value}`)}/>
  );
};

ListPicker.js

Here is the ListPicker component and the value when selected from the Picker is value and is set with setValue.

MY QUESTION: *How can I pass the value in my React Hook to my onValueChange in the parent component? Do I do that in the selectValue method?

// Imports: Dependencies
import React, { useState } from 'react';
import { Button, DatePickerAndroid, DatePickerIOS, Dimensions, Platform, Picker, SafeAreaView, StyleSheet, Text, View, TouchableOpacity } from 'react-native';
import Modal from 'react-native-modal';
import Icon from 'react-native-vector-icons/Ionicons';
Icon.loadFont();

// Screen Dimensions
const { height, width } = Dimensions.get('window');

// Component: List Picker
export const ListPicker = (props) => {
  // React Hooks: State
  const [ modalVisible, toggle ] = useState(false);
  const [ value, setValue ] = useState();

  // React Hooks: Lifecycle Methods



  // Toggle Modal
  toggleModal = () => {
    try {
      // React Hook: Toggle Modal
      toggle((modalVisible) => !modalVisible);
    }
    catch (error) {
      console.log(error);
    }
  };

  // Select Value
  selectValue = (value) => {
    try {
      // React Hook: Set Value
      setValue(value);

      // React Props: onValueChange
      // DO SOMETHING HERE??
    }
    catch (error) {
      console.log(error);
    }
  };

  // Render Picker Type
  renderPickerType = () => {
    try {
      // Check Platform (iOS)
      if (Platform.OS === 'ios') {

        return (
          <Picker
            selectedValue={value}
            onValueChange={this.selectValue}>
            {props.items.map((item) => {
              return (
                <Picker.Item
                  label={item.label}
                  value={item.value}
                  key={item.key || item.label}
                  color={item.color}
                />
              );
            })}
          </Picker>
        )
      }

      // Check Platform (Android)
      if (Platform.OS === 'android') {

      }
    }
    catch (error) {
      console.log(error);
    }
  };

  return (
    <View style={styles.container}>
      <View style={styles.inputTitleContainer}>
      <Text style={styles.inputTitle}>{props.listName}</Text>
      </View>

      <TouchableOpacity onPress={this.toggleModal} style={styles.fieldTextContainer}>
        <Text style={styles.fieldText}>{value !== undefined ? value : 'Select'}</Text>

        <Icon name="ios-arrow-forward" size={22} style={styles.arrowForward}/>
      </TouchableOpacity>

      <Modal
        isVisible={modalVisible}
        style={styles.modal}
      >
        <View style={styles.modalContainer}>
          <View style={styles.pickerHeaderContainer}>
            <TouchableOpacity onPress={this.toggleModal} >
              <Text style={styles.doneText}>Done</Text>
            </TouchableOpacity>
          </View>

          <View style={styles.pickerContainer}>
            {this.renderPickerType()}
          </View>
        </View>
      </Modal>
    </View>
  );
}

// Styles
const styles = StyleSheet.create({
  container: {
    display: 'flex',
    width: width - 32,
    marginLeft: 16,
    marginRight: 16,
    justifyContent: 'center',
  },
  modal: {
    margin: 0,
  },
  modalContainer: {
    height: '100%',
    alignItems: 'center',
    justifyContent: 'flex-end',
  },
  pickerHeaderContainer: {
    display: 'flex',
    flexDirection: 'row',
    justifyContent: 'flex-end',
    alignItems: 'center',
    height: 40,
    width: width,
    backgroundColor: '#FAFAF8',
    borderColor: '#7D7D7D',
    borderBottomWidth: StyleSheet.hairlineWidth,
  },
  pickerContainer: {
    height: 220,
    width: width,
    // backgroundColor: '#CFD3D9',
    backgroundColor: 'white',
  },
  doneText: {
    fontFamily: 'System',
    color: '#007AFF',
    fontWeight: '600',
    fontSize: 17,
    marginRight: 16,
  },
  stateContainer: {
    alignItems: 'center',
    width: 75,
    borderColor: '#7D7D7D',
    borderBottomWidth: StyleSheet.hairlineWidth,
  },
  inputTitleContainer: {
    width: 75,
    marginBottom: 4,
  },
  inputTitle: {
    color: '#7D7D7D',
    borderColor: '#7D7D7D',
    fontSize: 10,
    fontWeight: '600',
    textTransform: 'uppercase',
  },
  fieldTextContainer: {
    height: 40,
    display: 'flex',
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center',
    marginBottom: 4,
    borderColor: '#7D7D7D',
    borderBottomWidth: StyleSheet.hairlineWidth,    
  },
  fieldText: {
    fontFamily: 'System',
    fontSize: 17,
    fontWeight: '400',
    color: '#000000',
    alignSelf: 'center',
  },
  arrowForward: {
    color: 'black',
    opacity: .3,
    marginRight: 7,
  },
});

Upvotes: 2

Views: 1533

Answers (2)

vitalyster
vitalyster

Reputation: 5266

onValueChange is a function which you need to call when you need to pass new value to parent component, according to your code:

// DO SOMETHING HERE??

just props.onValueChange(value)

Upvotes: 1

Tan Dat
Tan Dat

Reputation: 3117

Yes. Just call the props.onValueChange with the changed value inside selectValue method.

  // Select Value
  selectValue = (value) => {
      // React Hook: Set Value
      setValue(value);

      // React Props: onValueChange
      props.onValueChange(value)
  };

BTW, You don't need to use try catch everywhere :D

Upvotes: 2

Related Questions