4.12 communication component child parent ascending.

In this lesson we wire child-to-parent communication: we want the new expense data collected inside ExpenseForm to bubble up first to NewExpense, then all the way up to App. The mechanism is exactly the same as for props going down — we just pass functions instead of values.

Adding the onSaveExpenseData prop

  • In NewExpense, render the form with <ExpenseForm onSaveExpenseData={saveExpenseDataHandler} />. The name starts with on to flag that the value must be a function.
  • Define saveExpenseDataHandler as an arrow function that takes enteredExpenseData as its parameter.
  • Build an enriched object with the spread operator and a generated id: const expenseData = { ...enteredExpenseData, id: Math.random().toString() };.
const saveExpenseDataHandler = (enteredExpenseData) => {
  const expenseData = {
    ...enteredExpenseData,
    id: Math.random().toString(),
  };
  props.onAddExpense(expenseData);
};

The three little dots are JavaScript's spread operator: they extract every key/value pair from enteredExpenseData and copy them into the new object, then we add a fresh id on top. The id generated with Math.random().toString() is not perfectly unique in theory, but it is good enough for our tracker.

Inside ExpenseForm, instead of logging the data with console.log, we now forward it through the prop we received: replace the previous log by props.onSaveExpenseData(expenseData);. The form no longer keeps the data for itself — it hands it over to its parent.

Finally, in App.js, we define an addExpenseHandler arrow function that receives the expense and, for now, simply logs it: console.log('In App.js'); console.log(expense);. We pass it down to NewExpense as <NewExpense onAddExpense={addExpenseHandler} />, and inside NewExpense we call props.onAddExpense(expenseData) from within saveExpenseDataHandler. Submit the form on your website and you should now see the new expense logged from App.js — proof that data has travelled from the deepest child all the way up to the top-level component. See you in the next lesson.

Summary

This lesson demonstrates how to implement upward data flow in React by passing callback functions as props from parent to child components. The parent defines a handler function and passes it to the child, which then calls that function with data whenever a specific action occurs. The example uses the spread operator to enrich the data before sending it upward, and shows how to use Math.random() to generate unique identifiers for each item.

Key points

  • Define callback functions in the parent component to handle data from child components
  • Pass callback functions as props to child components, following the convention of prefixing with 'on' (e.g., onSaveDespense)
  • Use the spread operator (...) to expand and merge data objects before passing them to parent handlers
  • Child components invoke the callback function with data as arguments to communicate changes upward
  • Parent components receive and process the data passed from children through callback execution
  • Use Math.random() for simple unique ID generation, understanding its limitations for production use

FAQ

How do you pass data from a child component to a parent component in React?

You pass a callback function as a prop from the parent to the child. The child component calls this function and passes the data as an argument, allowing the parent to receive and handle the data.

What is the spread operator (...) used for in this context?

The spread operator is used to expand an object and add new properties to it. In this lesson, it is used to take existing data and add a new 'id' property before sending the enriched object to the parent handler.

Why is the callback prop named with an 'on' prefix?

The 'on' prefix is a React convention that indicates the prop is an event handler or callback function that will be triggered when a specific action occurs in the child component.