Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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>
        )
    }
}
like image 829
ChaseHardin Avatar asked Jul 27 '17 19:07

ChaseHardin


People also ask

How do you pass parameters in callback function in React?

Passing the event object of react as the second argument. If you want to pass a parameter to the click event handler you need to make use of the arrow function or bind the function. If you pass the argument directly the onClick function would be called automatically even before pressing the button.

How do I call a callback function in React JS?

The React useCallback Hook returns a memoized callback function. Think of memoization as caching a value so that it does not need to be recalculated. This allows us to isolate resource intensive functions so that they will not automatically run on every render.

When to use React's usecallback hook?

Using React's useCallback hook is essentially just a wrapper around useMemo specialized for functions to avoid constantly creating new function instances within components' props. My question comes from when you need to pass an argued to the callback created from the memoization.

Is it necessary to bind callbacks in react?

TL;DR: Binding callbacks is a JavaScript thing. It’s necessary because you have to tell your callback what it’s context is. Avoid binding by using the public class fields syntax, or bind your callbacks inside the constructor. First of all, it’s not a React thing that you’ve got to bind this.

Is it OK to pass parameters to callback functions in JavaScript?

Generally speaking, yes, it is OK, and it is often the easiest way to pass parameters to callback functions. If you do have performance issues, by all means, optimize!

How do I use memoized callback in react functions?

const Button: React.FunctionComponent = props => { const onClick = React.useCallback ( () => alert ('Clicked!'), []) return <button onClick= {onClick}> {props.children}</button> } is a simple example of a memoized callback and required no external values passed into it in order to accomplish its job.


3 Answers

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}/>
like image 99
Prakash Sharma Avatar answered Oct 19 '22 19:10

Prakash Sharma


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

like image 1
marzelin Avatar answered Oct 19 '22 19:10

marzelin


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.

like image 1
error404 Avatar answered Oct 19 '22 19:10

error404