Code Monkey home page Code Monkey logo

react-hooks-information-flow-code-along's Introduction

React Information Flow

Learning Goals

  • Understand the flow of information between components with props
  • Use callback functions as props to update state in a parent component

Introduction

In this lesson, we'll explore how to pass callback functions as props in order to change state in a parent component.

How Does Information Flow Between Components?

We already know how to use props to pass information down from parent to child. But how would we do the reverse? How might we have a child component send data up to its parent component?

In order to propagate information in the opposite direction, we can send a callback function as props from the parent component to its child.

This allows the callback to be owned by a different component than the one invoking it. Once invoked, the callback can send data to or change state in the parent component that owns it, instead of the child component that invoked it.

Getting Started

Assuming you've pulled down the starter code and ran npm install and npm start, you should see a few rectangles in your browser. The large outer rectangle will be a random color every time you refresh the page, but the two smaller rectangles inside will always have a white background.

Take a moment to familiarize yourself with the code base. We have a simple application that renders a single Parent component and two Child components. The component hierarchy is as follows:

App
└───Parent
    ├───Child
    └───Child

Deliverables Part 1

  • When either Child component is clicked, the Parent component should change color.

src/randomColorGenerator.js has a helper function getRandomColor() implemented for you that generates a random color.

Changing the color of Parent

The Parent component has a state variable called color that is initially set to a random color. To update state, we'll create a simple handleChangeColor function:

function Parent() {
  const randomColor = getRandomColor();
  const [color, setColor] = useState(randomColor); // initial value for color state

  function handleChangeColor() {
    const newRandomColor = getRandomColor();
    setColor(newRandomColor); // update color state to a new value
  }

  return (
    <div className="parent" style={{ backgroundColor: color }}>
      <Child />
      <Child />
    </div>
  );
}

But we are going to want to run this handleChangeColor() function when either Child component is clicked. So we are going to pass this state changing function as a prop to both Child components.

return (
  <div className="parent" style={{ backgroundColor: color }}>
    <Child onChangeColor={handleChangeColor} />
    <Child onChangeColor={handleChangeColor} />
  </div>
);

Now, Child will have a prop called onChangeColor that is a function. Specifically, it is the same function object as our Parent's handleChangeColor function. Want to see for yourself? Put a console.log inside the Child component.

function Child({ onChangeColor }) {
  console.log(onChangeColor);
  return <div className="child" style={{ backgroundColor: "#FFF" }} />;
}

We can now use this onChangeColor prop as an event handler:

console.log(onChangeColor);
return (
  <div
    onClick={onChangeColor}
    className="child"
    style={{ backgroundColor: "#FFF" }}
  />
);

And ta-da! Now, if you go to the app, clicking on either of the white rectangle Child components will cause the Parent component to change color.

Let's walk though those steps:

  • When the div in the Child component is clicked, it will use the onChangeColor variable to determine what function to run
  • onChangeColor is a prop that is passed down from the Parent component, which references the handleChangeColor function
  • The handleChangeColor function is the function that will actually run when the div is clicked, and will update state in the Parent component

Now, let's add one more feature!

Deliverables Part 2

  • When either Child component is clicked, it should change its own background color to a random color, and the other Child component should change to that same color.

Now, we could put some state in our Child component to keep track of its color. However:

  • Sibling components cannot pass data to each other directly
  • Data can only flow up and down between parent and child

So if we update the color of one Child component, we have no way to pass that data to the other Child component.

The solution is to store the color of the Child in the state of the Parent component. Then, we let the Parent component handle the passing of that data to each of its children components. We'll start by creating a variable to keep track of the color of the Child components using state:

function Parent() {
  const randomColor = getRandomColor();
  const [color, setColor] = useState(randomColor);
  const [childrenColor, setChildrenColor] = useState("#FFF");

  // ...
}

Since the data that represents the color of the two Child components lives in Parent, we should pass that data down as props:

return (
  <div className="parent" style={{ backgroundColor: color }}>
    <Child color={childrenColor} onChangeColor={handleChangeColor} />
    <Child color={childrenColor} onChangeColor={handleChangeColor} />
  </div>
);

Now let's actually use that props data in the Child component:

function Child({ onChangeColor, color }) {
  return (
    <div
      onClick={onChangeColor}
      className="child"
      style={{ backgroundColor: color }}
    />
  );
}

Lastly, we have to update the handleChangeColor() function in Parent to change not just the color state, but also the childrenColor. To practice sending data back to the parent, let's change our handleChangeColor to take in an argument of newChildColor and then use that variable to update the state of the Child component:

function handleChangeColor(newChildColor) {
  const newRandomColor = getRandomColor();
  setColor(newRandomColor);
  setChildrenColor(newChildColor);
}

Now that the function takes in an argument, we can create a new function in our Child component that invokes onChangeColor and passes in a random color as the argument; we also need to update the component's onClick callback to be that new function:

function Child({ onChangeColor, color }) {
  function handleClick() {
    const newColor = getRandomColor();
    onChangeColor(newColor);
  }

  return (
    <div
      onClick={handleClick}
      className="child"
      style={{ backgroundColor: color }}
    />
  );
}

Wow! Check out the finished product in the browser! When either Child component is clicked, the Parent changes to a random color, and both Child components change to a different random color.

Conclusion

For information to propagate down the component tree, parents pass props to their children.

For information to propagate up the component tree, we must invoke callbacks that were passed from parents to children as props. When invoking the callback, we can pass any needed values from the child component to the parent component as arguments.

Components of the same level (sibling components) cannot communicate directly! We can only communicate up and down the component tree. So if multiple components need to share the same information, that state should live in the parent component (or a more general ancestor).

Resources

react-hooks-information-flow-code-along's People

Contributors

danielseehausen avatar dependabot[bot] avatar ihollander avatar jlboba avatar lizbur10 avatar maxwellbenton avatar rrcobb avatar thuyanduong-flatiron avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

react-hooks-information-flow-code-along's Issues

Maybe Conclusion can highlight opportunity to pass child values to parents via arguments to callbacks

Canvas Link

https://learning.flatironschool.com/courses/5186/assignments/180088?module_item_id=397501

Concern

This statement in the conclusion is fine:
For information to propagate up the component tree, we must invoke callbacks that were passed from parents to children as props.

However, you might extend it to emphasize the ability to pass child information to parents as arguments for the callbacks we are invoking:
onChangeColor(newColor);

This was kind of an "Aha" moment for me.

Additional Context

No response

Suggested Changes

Maybe extend this statement:
For information to propagate up the component tree, we must invoke callbacks that were passed from parents to children as props.

to something like this:
For information to propagate up the component tree, we must invoke callbacks that were passed from parents to children as props. In the process, we can pass values of child variables as arguments when invoking those callbacks. (Shades of passing props from parents!)

handleChangeColor() : getting two different Colors

The function handleChangeColor was getting the same color for the child and parent components. When clicking, they all change to the same random color. To make it work, I called getRandomColor a second time for the child to get a different random color.
Is this a good solution, or is there a better way of getting two different random colors?

function handleChangeColor() {
const newRandomColor = getRandomColor();
const newChildRandomColor = getRandomColor();
setColor(newRandomColor);
setChildrenColor(newChindRandomColor);
}

picture in scrimba brokwn

Canvas Link

https://learning.flatironschool.com/courses/4385/modules/items/310712

Concern

The module page with the Scrimba doesn't have a flag icon to report new issues on so I am reporting it here, on the page that follows in the State and Events module. In the first video of Scrimba Playlist: Thinking in React, at about 1 min 30 sec left, the speaker pastes in a URL or file path for a picture in that does not render in the console. He references this picture throughout the rest of the video to explain things and into the next but the picture isn't showing up (alt text shows instead). Video is hard to follow without seeing the picture he is referencing.

Additional Context

No response

Suggested Changes

No response

Broken URL in Scrimba video

Canvas Link

https://learning.flatironschool.com/courses/4986/modules/items/357570

Concern

This link is broken: https://reactjs.org/static/eb8bda25806a89ebdc838813bdfa3601/6b2ea/thinking-in-react-components.png

It is included in the first Scrimba video at the above Canvas Link:
Thinking in React: Step 1 - Component Hierarchy

This means that everything discussed regarding this link in the video is missing context

Additional Context

No response

Suggested Changes

Find the correct URL

newChildColor is not working

Thanks for raising this issue! Future learners thank you for your diligence. In
order to help the curriculum team address the problem, please use this template
to submit your feedback. We'll work on addressing the issue as soon as we can.

Please fill out as much of the information below as you can (it's ok if you
don't fill out every section). The more context we have, the easier it will be
to fix your issue!

Note: you should only raise issues related to the contents of this lesson.
If you have questions about your code or need help troubleshooting, reach out to
an instructor/your peers.


Link to Canvas

https://learning.flatironschool.com/courses/3532/assignments/124154?module_item_id=255835

Describe the bug

In Deliverables Part 2, newChildColor is throwing an error: src/Parent.js
Line 6:38: 'newChildColor' is not defined no-undef

There's no way to currently see the expected result.

What is the expected behavior?

The page should load with no errors.

Screenshots

If applicable, attach screenshots to help explain your problem.

What OS are you using?

  • OS X
  • [ X ] WSL
  • Linux

Any additional context?

Add any other context about the problem here.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.