ORStudios
ORStudios

Reputation: 3233

Passing input text back to parent from component

I am using an auto expanding text input field (Link) and I am creating it as a component. My question is when the text is changed how do I pass the value of the data back to the parent? I want to be able to submit the input via the parent so I was thinking of storing the input value in the parents state.

Parent

Calling the child component by using <InputExpand />

render() {

    const { navigate } = this.props.navigation;

    console.log("Rendering");

    return (
        <KeyboardAvoidingView behavior="padding" style={{flex: 1}}>
        <View style={{flex: 1}}>
            <StatusBar hidden={true} />
            <View style={styles.headerBar}>
                <NavBar navigation={this.props.navigation} goBack={this.goBack} title="MESSAGE DETAILS" backButton={true} showNewMessage={true} />
            </View>
            <View style={styles.contentWrapper}>
                <ListView
                        dataSource={this.state.dataSource}
                        renderRow={this.renderRow}
                        enableEmptySections={true}
                        style={styles.listWrapper}
                    />
            </View>
            <View style={styles.footerBar}>
                    <View style={styles.footerBtnContainer}></View>
                    <View style={styles.footerInputContainer}>
                        <InputExpand />
                    </View>
                    <View style={styles.footerBtnContainer}>
                        <Image source={require('../../images/icons/IconSend.png')} style={{width: 20, height: 20}}/>
                    </View>
            </View>
        </View>
        </KeyboardAvoidingView>
    );
  }

Component - (Child)

import React, { Component } from 'react'

const {
  TextInput,
  StyleSheet,
} = require('react-native');

export default class AutoExpandingTextInput extends React.Component {
  state: any;

  constructor(props) {
    super(props);
    this.state = {text: '', height: 0};
  }
  render() {
    return (
      <TextInput
        {...this.props}
        multiline={true}
        onChange={(event) => {
          this.setState({
            text: event.nativeEvent.text,
            height: event.nativeEvent.contentSize.height,
          });
        }}
        style={[styles.default, {height: Math.max(35, this.state.height)}]}
        value={this.state.text}
        placeholder={"Type a message..."}
        placeholderTextColor={"#fff"}
      />
    );
  }
}

var styles = StyleSheet.create({
  default: {
    color: "#fff",
    fontSize: 10,
    fontFamily: "Avenir-Light",
  },
});

Upvotes: 2

Views: 2950

Answers (2)

Mμ.
Mμ.

Reputation: 8542

Yes, that is exactly what you should do. You create a handler in the parent state and pass it into the child component as a prop.

// parent component

// assuming a property inputText exists in the state
// and use arrow function to preserve the context of `this` to be of the parent class.
onChangeTextHandler = (e) => {
  this.setState({
    // get the value from TextInput onChangeText event
    inputText: e.value, 
  })
}

render() {

    const { navigate } = this.props.navigation;

    console.log("Rendering");

    return (
        <KeyboardAvoidingView behavior="padding" style={{flex: 1}}>
        <View style={{flex: 1}}>
            <StatusBar hidden={true} />
            <View style={styles.headerBar}>
                <NavBar navigation={this.props.navigation} goBack={this.goBack} title="MESSAGE DETAILS" backButton={true} showNewMessage={true} />
            </View>
            <View style={styles.contentWrapper}>
                <ListView
                        dataSource={this.state.dataSource}
                        renderRow={this.renderRow}
                        enableEmptySections={true}
                        style={styles.listWrapper}
                    />
            </View>
            <View style={styles.footerBar}>
                    <View style={styles.footerBtnContainer}></View>
                    <View style={styles.footerInputContainer}>
                        <InputExpand onChangeTextHandler= {this.onChangeTextHandler}/>
                    </View>
                    <View style={styles.footerBtnContainer}>
                        <Image source={require('../../images/icons/IconSend.png')} style={{width: 20, height: 20}}/>
                    </View>
            </View>
        </View>
        </KeyboardAvoidingView>
    );
  }

// Child Component
import React, { Component } from 'react'

const {
  TextInput,
  StyleSheet,
} = require('react-native');

export default class AutoExpandingTextInput extends React.Component {
  state: any;

  constructor(props) {
    super(props);
    this.state = {text: '', height: 0};
  }
  render() {
    const { onChangeTextHandler } = this.props;
    return (
      <TextInput
        {...this.props}
        multiline={true}
        onChange={(event) => {
          // set the state of parent component here...
          onChangeTextHandler(event.nativeEvent.text);
          this.setState({
            text: event.nativeEvent.text,
            height: event.nativeEvent.contentSize.height,
          });
        }}
        style={[styles.default, {height: Math.max(35, this.state.height)}]}
        value={this.state.text}
        placeholder={"Type a message..."}
        placeholderTextColor={"#fff"}
      />
    );
  }
}

var styles = StyleSheet.create({
  default: {
    color: "#fff",
    fontSize: 10,
    fontFamily: "Avenir-Light",
  },
});
reactjs react-native

Upvotes: 4

Sergio D.
Sergio D.

Reputation: 46

You should pass via props a callback for handle input text changes to the component, and use the onChange event of the input text to call that handle from the child component. If the input text doesn't have onChange (or something like that) you could use a onKeyUp. But the general idea is that you send a callback via props from the parent to the child, and you call it from the child to send data to the parent.

Upvotes: 0

Related Questions