user709413
user709413

Reputation: 515

Updating Parent Component via Child Component in React Native

I have a parent component and two child components. One of the child components is a form with an add button. I am able to capture the text when add button is pressed, but stuck when trying to pass that value to the parent component, update the array in parent component and re-render the view.

Parent Component:

var Tasks = ['Competitor Study','Content Plan','Write','Promote','Consumer Research']

//Build React Component
class MyTaskList extends Component {

render() {
    return (
      <View style={styles.container}>
         <Text style={styles.titleStyle}>
          My Tasks  
          {"\n"} 
            ({Moment().format("MMM Do YY")})
          {"\n"}
        </Text>
        <AddTask />
        {this.workitems()}
      </View>
    );
  }

  workitems() {  
   return (Tasks.map(function(workitem,i) {
    return <ListItem key={i} workitem={workitem} />
        }
      )
    );  
  }

}

Child component with the form

class AddTask extends Component {

    constructor(props) {
      super(props);
      this.state = {
        enterTask: 'Enter task'
      };
    }

    onTaskTextChanged(event) {
      this.setState({ enterTask: event.nativeEvent.text });
    }

    onAddPress() {
     var newtask = this.state.enterTask;
     console.log('new task - '+newtask);
    }

    render() {
        return (
            <View style={styles.addTask}>
                   <TextInput
                    style={styles.taskInput}
                    value={this.state.enterTask}
                    onChange={this.onTaskTextChanged.bind(this)}
                    placeholder='Enter task'/>
                 <TouchableHighlight style={styles.button}
                    onPress={this.onAddPress.bind(this)}
                    underlayColor='#99d9f4'>
                    <Text style={styles.buttonText}>Add</Text>
                </TouchableHighlight>
            </View>
        );
    }
}

Upvotes: 1

Views: 4753

Answers (2)

David
David

Reputation: 7525

I would instead use state for this as using forceUpdate() is not recommended

From React docs:

Calling forceUpdate() will cause render() to be called on the component, skipping shouldComponentUpdate(). This will trigger the normal lifecycle methods for child components, including the shouldComponentUpdate() method of each child. React will still only update the DOM if the markup changes.

Normally you should try to avoid all uses of forceUpdate() and only read from this.props and this.state in render(). This makes your component "pure" and your application much simpler and more efficient.

(Based off of @1ven answer)

Parent Component:

//Build React Component
class MyTaskList extends Component {

    constructor(props) {
        super(props);

        this.state = {
            tasks: [
                'Competitor Study',
                'Content Plan',
                'Write','Promote',
                'Consumer Research'
            ]
        } 
    }

    handleAddTask(task) {
        var newTasks = Object.assign([], this.state.tasks);
        newTasks.push(task);
        this.setState({tasks: newTasks});
    }

    render() {
        return (
            <View style={styles.container}>
                <Text style={styles.titleStyle}>
                    My Tasks  
                    {"\n"} 
                    ({Moment().format("MMM Do YY")})
                    {"\n"}
                </Text>
                <AddTask onAddTask={this.handleAddTask.bind(this)} />
                {this.workitems()}
            </View>
        );
    }

    workitems() {  
        return this.state.tasks.map(function(workitem,i) {
            return <ListItem key={i} workitem={workitem} />
        });
  
    }
}

Child component with the form

class AddTask extends Component {
    constructor(props) {
        super(props);
        this.state = {
            enterTask: 'Enter task'
        };
    }

    onTaskTextChanged(event) {
        this.setState({ enterTask: event.nativeEvent.text });
    }

    onAddPress() {
        var newtask = this.state.enterTask;
        console.log('new task - '+newtask);
        // Providing `newtask` variable to callback.
        this.props.onAddTask(newtask);
    }

    render() {
        return (
            <View style={styles.addTask}>
                <TextInput
                    style={styles.taskInput}
                    value={this.state.enterTask}
                    onChange={this.onTaskTextChanged.bind(this)}
                    placeholder='Enter task'/>
                <TouchableHighlight style={styles.button}
                    onPress={this.onAddPress.bind(this)}
                    underlayColor='#99d9f4'>
                   <Text style={styles.buttonText}>Add</Text>
                </TouchableHighlight>
            </View>
        );
    }
}

Upvotes: 1

1ven
1ven

Reputation: 7026

You should provide handleAddTask callback from parent to child component:

var Tasks = ['Competitor Study','Content Plan','Write','Promote','Consumer Research']

//Build React Component
class MyTaskList extends Component {

  handleAddTask(task) {
    // When task will be added, push it to array
    Tasks.push(task);
  }

  render() {
    return (
      <View style={styles.container}>
        <Text style={styles.titleStyle}>
          My Tasks  
          {"\n"} 
          ({Moment().format("MMM Do YY")})
          {"\n"}
        </Text>
        <AddTask onAddTask={this.handleAddTask} />
        {this.workitems()}
      </View>
    );
  }

  workitems() {  
    return (
      Tasks.map(function(workitem,i) {
        return <ListItem key={i} workitem={workitem} />
      })
    );  
  }
}

Next, you should pass task from child component to this callback:

class AddTask extends Component {
  constructor(props) {
    super(props);
    this.state = {
      enterTask: 'Enter task'
    };
  }

  onTaskTextChanged(event) {
    this.setState({ enterTask: event.nativeEvent.text });
  }

  onAddPress() {
    var newtask = this.state.enterTask;
    console.log('new task - '+newtask);
    // Providing `newtask` variable to callback.
    this.props.onAddTask(newtask);
  }

  render() {
    return (
      <View style={styles.addTask}>
        <TextInput
          style={styles.taskInput}
          value={this.state.enterTask}
          onChange={this.onTaskTextChanged.bind(this)}
          placeholder='Enter task'/>
        <TouchableHighlight style={styles.button}
          onPress={this.onAddPress.bind(this)}
          underlayColor='#99d9f4'>
          <Text style={styles.buttonText}>Add</Text>
        </TouchableHighlight>
      </View>
    );
  }
}

That's it. Hope, it helps!

Upvotes: 0

Related Questions