ChaseHardin
ChaseHardin

Reputation: 2269

Callback Function With Parameters ReactJS

Working with ReactJS and having trouble understanding how callback functions work with ReactJS.

I have a parent component titled TodoFormComponent, which initializes my list of todo items. I've created a callback function on the TodoItemsComonent, but it doesn't trigger the updateItem method and display the selected item.

Question: How can I pass data from the child to the parent? I want to pass the selected todo item to the parent so that I can update the master todo list.


Parent Component (TodoFormComponent)


The TodoFormComponent has selectedTask, which should be triggering the updateItem method.

import * as React from "react";
import TodoItemsComponent from "../todo-items/todo-items.component";
import AddTodoItemComponent from "../add-todo-item/add-todo-item.component";

export default class TodoFormComponent extends React.Component {
    constructor(){
        super();
        this.state = {
            todoItems: [
                { id: '1', todo: 'First Todo Item' },
                { id: '2', todo: 'Second Todo Item' },
                { id: '3', todo: 'Third Todo Item' }
            ],
            selected: {}
        };

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

    updateItem () {
        console.log('Selected Value:: ', this.state.selected);
    }

    render() {
        return (
            <div className="row">
                <div className="container">
                    <div className="well col-xs-6 col-xs-offset-3">
                        <h1>To do: </h1>
                        <div name="todo-items">
                            <TodoItemsComponent items={this.state.todoItems} selectedTask={() => {this.updateItem}}/>
                        </div>
                        <div name="add-todo-item">
                            <AddTodoItemComponent/>
                        </div>
                    </div>
                </div>
            </div>
        )
    }
}

Child Component (TodoItemsComponent)


The TodoItemsComponent has an onClick to update the selected value. This gets updated in the selectedTask function. import * as React from "react";

export default class TodoItemsComponent extends React.Component {
    constructor(props) {
        super(props);
    }

    selectedTask (item) {
        this.setState({selected: item})
    }

    render() {
        return (
            <ul className="list-group">
                {
                    this.props.items.map((item) => {
                        return (
                            <li className="list-group-item">
                                {item.todo}
                                <div className="pull-right">
                                    <button
                                        type="button"
                                        className="btn btn-xs btn-success">
                                        &#x2713;
                                    </button> <button
                                        type="button"
                                        className="btn btn-xs btn-danger"
                                        onClick={() => {this.selectedTask(item)}}
                                        >&#xff38;
                                    </button>
                                </div>
                            </li>
                        )
                    })
                }
            </ul>
        )
    }
}

Upvotes: 8

Views: 48272

Answers (5)

Prakash Sharma
Prakash Sharma

Reputation: 16472

Whenever you want to pass data from child to parent you pass a function as a prop to child and from child you call that function using this.props.passedFunction(yourDataToPassToParent)

Here from your parent component you are passing the selectedTask function as prop, so you should call this.prop.selectedTask() with the data to be passed to parent like:

<button
  type="button"
  className="btn btn-xs btn-danger"
  onClick={() => {this.props.selectedTask(item)}}
 >
  &#xff38;
 </button>

Also the way you are passing the selectedTask in your parent is wrong. You should pass it like this:

<TodoItemsComponent items={this.state.todoItems} selectedTask={this.updateItem}/>

Upvotes: 17

error404
error404

Reputation: 331

In your TodoItemsComponent,updateItem() is passed as prop. So you need to call the this.props.updateItem()in your onClick method.

So your button should be:

                 <button
                 type="button"
                 className="btn btn-xs btn-danger"
                 onClick={() => 
                     {this.props.selectedTask(item)}}>&#xff38;
                 </button>

and Update your parent components UpdateItem method to receive properties as item. Like this:

updateItem (e) {
    console.log('Selected Value:: ', e);
}

And to pass method in children you need to

             <TodoItemsComponent items=
                 {this.state.todoItems} selectedTask={this.updateItem}/>

If you do this: {()=>this.updateItem()} then it will initialize the method. So you need just pass the function reference.

Upvotes: 1

marzelin
marzelin

Reputation: 11600

fixed code:

class TodoItemsComponent extends React.Component {
  constructor(props) {
    super(props);
  }

  render() {
    return (
      <ul className="list-group">
        {this.props.items.map(item => {
          return (
            <li className="list-group-item">
              {item.todo}
              <div className="pull-right">
                <button type="button" className="btn btn-xs btn-success">
                  &#x2713;
                </button>{" "}
                <button
                  type="button"
                  className="btn btn-xs btn-danger"
                  onClick={() => {
                    this.props.selectedTask(item);
                  }}
                >
                  &#xff38;
                </button>
              </div>
            </li>
          );
        })}
      </ul>
    );
  }
}

class TodoFormComponent extends React.Component {
  constructor() {
    super();
    this.state = {
      todoItems: [
        { id: "1", todo: "First Todo Item" },
        { id: "2", todo: "Second Todo Item" },
        { id: "3", todo: "Third Todo Item" }
      ],
      selected: {}
    };

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

  updateItem(item) {
    this.setState({ selected: item });
  }

  render() {
    return (
      <div className="row">
        <div className="container">
          <div className="well col-xs-6 col-xs-offset-3">
            <h1>To do: </h1>
            <h3>
              Selected task: {JSON.stringify(this.state.selected)}
            </h3>
            <div name="todo-items">
              <TodoItemsComponent
                items={this.state.todoItems}
                selectedTask={this.updateItem}
              />
            </div>
            <div name="add-todo-item" />
          </div>
        </div>
      </div>
    );
  }
}

const App = () => <TodoFormComponent />;

ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>

playground: https://codesandbox.io/s/LgrGKK9og

Upvotes: 1

Kamil Socha
Kamil Socha

Reputation: 299

Some pseudo-code:

class Parent extends React.Component {
    render() {
        return (<Child id={1} onClick={(id) => console.log(id)}/>);
    }
}

class Child extends React.Component {
    render() {
        return (<div onClick={() => this.props.onClick(this.props.id)}></div>);
    }
}

Console.log will output "1"

More: link

Upvotes: 0

pethel
pethel

Reputation: 5537

You have to send updateItem as a prop to the child Component.

const Parent = () => 
<div>
  <TodoItemsComponent items={this.state.todoItems} selectedTask={updateItem}/>
</div>

Also update

updateItem (item) {  
   this.setState({ selected: item })
   console.log( 'Selected Value:: ', item);
}

Upvotes: 0

Related Questions