We've just hit another one of those very important moments. The parent component passes data down to the child via props. Thanks to this, the child component can be really dumb! It just receives props and renders them. That's it. Importantly, the child never communicates back up to the parent. Heck, the RepLogList component doesn't even know who its parent is! And, in theory, we could render RepLogList from 10 different parent components!

So... that leaves us in a pickle: inside onClick, we need to update the highlightedRowId state on our parent component. How can a child component update the state of a parent? The answer: it can't!

Wait wait, it's not time to panic... yet. Remember: the child component doesn't know who its parent is... heck! It doesn't even know that highlightedRowId is something that is stored in state! RepLogList just says:

I don't know, I'm just a React component. Somebody passes me a highlightedRowId prop and I render it. I don't know and I don't really care if it's stored in state.

So, how can we solve this problem? In the same way that we pass data from a parent component to a child component, we can also pass callback functions from parent to child. The child can effectively notify the parent when something happens by calling that function!

It's best to see this in action. First, just to clean things up, in the handler function, remove the event argument: we were never using this anyways. Next, down where we render RepLogList, let's break this into multiple lines. Then pass in another prop called onRowClick set to this.handleRowClick. But, make sure you don't call that function: just pass it as a reference.

Thanks to this, in the child component, we have a fancy new onRowClick prop. Destructure this into a new variable. Then, onClick, we're dumb: we don't know anything about state, but we do know that we're passed an onRowClick prop, and that we're supposed to call this when the row is clicked! Cool! Call it and pass it repLog.id.

That's it! When the user clicks the row, our dumb component will execute the callback and pass the rep log id. The parent maintains complete control of what to do when this happens.

Let's try it! Move over and refresh. Bah! We still have an error:

Cannot read property setState() of undefined

Whoops! Whenever we have a callback handler function, we need to guarantee that the this keyword is bound to this object. There are a few ways to do this, but I usually fix this in one consistent way: go to the constructor and add this.handleRowClick = this.handleRowClick.bind(this).

Now, no matter who calls this method, this will always refer to this RepLogApp instance.

Refresh one more time. And, click! We got it!

We just saw a massively important pattern. Our state lives on our top level component. Then, we communicate to our children by passing data as props and we allow those children to communicate back to the parent component by passing them callback functions that should be executed when some interaction happens.

Oh, and by following this pattern, we've started to identify two types of components: stateful smart component and stateless dumb components. An important distinction we'll talk about next.

Leave a comment!

2018-10-22weaverryan

Haha, yep :). Well... bad habit. And actually, in a few cases, when I switched over, I was too quick, and the page *hadn't* refreshed yet (and it was still finishing building, so wouldn't refresh for another second or two) and then the feature wouldn't work as expected. So... I took the "hardcore" option to avoid any issues :).

But I do say refresh a lot. I try to find other words to use... because it's even weird for me to say this so much! :D

2018-10-21Ivan Puntiy

> Refresh... Refresh... Refresh...

Few videos ago you switched encore to dev-server = there's no need to refresh now...