DEV Community

Chukwuma Anyadike
Chukwuma Anyadike

Posted on • Updated on

Information Flow in React: Making a Callback() to Children and Giving Them Props

It is often said that communication is a two way street. It is true between friends, family, and significant others. In React, this is especially true. This is true because applications consists of multiple components. These components have to exchange data with one another to work harmoniously.

In order to understand information flow, it is important to understand component hierarchy. There are parent components and child components. The parent component renders child components. This is clearly demonstrated by the diagram below.

Parent
├───Child
└───Child

As code it looks like this.

import React from "react"
import Child from "./Child"

function Parent() {

  return (
    <div>
      <Child />
      <Child />
    </div>
  );

export default Parent;


import React from "react"

function Child() {
  return (
    <div>
      I am a child component
    </div>
  );
}

export default Child;
Enter fullscreen mode Exit fullscreen mode

Parent components can pass information to child components directly. They do this by giving them props. Props is short for properties. They are objects with key: value pairs. They are taken as arguments by components, which are functions. Props can make components more dynamic. By passing different props to a component, that component can render differently depending on the value of props. Take for example, the App component below.

import React, {useState, useEffect} from "react";
import AddHero from "./AddHero";
import DisplayHeroes from "./DisplayHeroes";

function App() {

  const [heroesList, setHeroesList]=useState([])

  useEffect(()=>{
    fetch("http://localhost:3000/heroes")
    .then(res=>res.json())
    .then(heroes=>setHeroesList(heroes))
}, [])

  function addNewHero(hero){
    setHeroesList(heroesList=>([...heroesList, hero]))
  }

  return (
    <div>
      <DisplayHeroes heroesList={heroesList} />
      <AddHero addNewHero={addNewHero} />
    </div>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

Here is the hierarchy below. The parent component App renders two child components: DisplayHeroes and AddHero.

App
├───DisplayHeroes
└───AddHero

The App component is passing down heroesList as props to DisplayHeroes. The props heroesList is an array of objects obtained via a fetch request. App component also passes down a callback function addNewHero as props to AddHero. I will discuss callback functions shortly.

The parent, App, directly passes props to the child, DisplayHeroes. DisplayHeroes will render a display of superhero profiles based on the information passed down. Also note that DisplayHeroes passes props (hero) to HeroProfile, making DisplayHeroes a parent to HeroProfile, a component which displays superhero profiles. It is clear that parent components directly pass information to child components.

import React, {useState} from "react";
import HeroProfile from "./HeroProfile";

function DisplayHeroes({heroesList}){

    const displayedHeroes = heroesList.map(hero=><HeroProfile key={hero.id} hero={hero} />)

    return (
        <div>
            <h1>Welcome To Our Superhero Codex</h1>
            {displayedHeroes}
        </div>
    )
}

export default DisplayHeroes;
Enter fullscreen mode Exit fullscreen mode

Here is what we get on our screen.

Superhero codex

It has been established that parent components directly pass information as props to child components. That is straight forward. However, child components cannot directly pass information to parent components. Furthermore, siblings cannot directly pass information to each other either. However, information can be indirectly sent from child to parent through callback functions. Let me explain how this works. Remember, that the App function passes a callback function, addNewHero, to the component AddHero from our example code above.

One thing to remember about functions in general is that they can be invoked anywhere that can access the function. However, functions are executed where they are defined. Think about it like this. A function is passed from the parent to the child as props. The original function was defined in the parent component. The child component now "has" the function as a prop and can invoke that function. When the child invokes the function it can pass data as arguments into the function. The function is executed in the parent component with access to the data from the child component. Hence, just like that, the child just "passed" data to the parent indirectly through a callback function provided by its parent. This is known as inverse data flow.

Let us take a closer look at the AddHero component. This is a controlled form which allows the user to add superhero information into the Superhero Codex.

import React from "react";
import { useState } from "react";

function AddHero ({addNewHero}){

    const [newHero, setNewHero] = useState({
        name: "",
        image: "",
        powers: "",
        weapons: "",
        team: "none",
        quote: ""
    })
    const {name, image, powers, weapons, quote} = newHero

    const navigate = useNavigate()

    function handleChange(event){
        setNewHero(newHero=>({...newHero, [event.target.name]:event.target.value}))
    }
    function handleSubmit(event){
        event.preventDefault()
        fetch("http://localhost:3000/heroes", {
                method: "POST",
                headers: {"Content-Type": "application/json"},
                body: JSON.stringify(newHero)
            })
            .then(res=>res.json())
            .then(hero=>addNewHero(hero))
    }

    const justiceLeagueSymbol = "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTpufklrQw-B7ZuUKU5AYSCcbd8saHgbE4T4Q&usqp=CAU"
    const avengersSymbol = "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQ0g1mLUq06zSJgaJfAHSSl-5EPVcW5ePwLvg&usqp=CAU"
    const xmenSymbol = "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRtGKOCC36vFkYH7eqXce66vtlJAkxxFSDR7g&usqp=CAU"

    return (
        <div className="registration">
            <h4>The world needs heroes like you.  Please register below.</h4>
            <form onSubmit={handleSubmit}>
                <label>Code Name </label>
                <input 
                    type="text" 
                    name="name" 
                    placeholder="Code Name" 
                    value={name} 
                    onChange={handleChange} 
                />
                <br/>
                <label>Image URL </label>
                <input 
                    type="text" 
                    name="image" 
                    placeholder="Image"
                    value={image} 
                    onChange={handleChange}
                />
                <br/>
                <label>Powers </label>
                <input 
                    type="text" 
                    name="powers" 
                    placeholder="Powers" 
                    value={powers} 
                    onChange={handleChange}
                />
                <br/>
                <label>Weapons </label>
                <input 
                    type="text" 
                    name="weapons" 
                    placeholder="Weapons" 
                    value={weapons} 
                    onChange={handleChange}
                />
                <br/>
                <label>Catch Phrase </label>
                <input 
                    type="text" 
                    name="quote" 
                    placeholder="Catch Phrase" 
                    value={quote} 
                    onChange={handleChange}
                />
                <br/>
                <label>Pick a team</label>
                <select name="team" onChange={handleChange}>
                    <option value="none"></option>
                    <option value="Justice League">Justice League</option>
                    <option value="Avengers">Avengers</option>
                    <option value="X-men">X-men</option>
                </select>
                <br/>
                <button type="submit">Register Now</button>
            </form>
            <div className="form-logos">
                <img src={justiceLeagueSymbol} alt="Justice League symbol" />
                <img src={avengersSymbol} alt="Avengers symbol" />
                <img src={xmenSymbol} alt="X-men symbol" />
            </div>
        </div>
    )
}

export default AddHero;
Enter fullscreen mode Exit fullscreen mode

This is what the form looks like on screen.

Superhero registration form

The information is entered on the form and stored in state as an object. The data looks very similar to this.

const newHero = {
        name: "Blade",
        image: "https://media3.giphy.com/media/l41m1bp1L7FpFtjTq/200w.gif?cid=6c09b9522sa3k9q0lroezc14g30aogg4mfm1abv46peu6c29&rid=200w.gif&ct=g",
        powers: "superhuman strength and speed, skilled martial artist",
        weapons: "sword",
        team: "Avengers",
        quote: "There are worse things out tonight than vampires."
    }
Enter fullscreen mode Exit fullscreen mode

This object is "passed" to the parent when the AddHero component invokes the addNewHero function at the end of the fetch after passing the newHero object as an argument. The function is executed in the parent component which adds the newHero object to heroesList in the App (parent component). The App component passes the heroesList to the DisplayHeroes component which subsequently re-renders and displays a new set of profiles with "Blade" newly added to the Superhero codex.

As one can see, we can do some fun things with information flow in react such as render a superhero codex and add new heroes to this codex.

Take away points:

  1. Parent components directly pass information to child components through props.
  2. Child components cannot directly pass information to parent components. However, they indirectly pass information to parent components through callback functions (passed as props by the parent). This is known as inverse data flow.
  3. Siblings cannot directly pass information to each other either. One child can "pass" information to the parent through a callback function. The parent then passes information to the other child (sibling) through props.

Thank you for your time. Now please callback the children and give them some props.

Top comments (0)