[SalesForce] Lightning Web Components: How to handle events from grand child on the owner(eventParent) component

I have 3 Lightning web components, Parent ->Child -> Grand child all with just a lightning button inside it.

eventParent:

<template>
<lightning-button
variant="brand"
label="Submitparent"
onclick={handleClick}>
</lightning-button> 
<c-event-child></c-event-child>
</template>

javascript file

import { LightningElement } from 'lwc';

export default class EventParent extends LightningElement {    
    handleClick() {
        alert('alert from parent');
    }
    handleNotify(){
        alert("received event from grand child even though i am the parent");
    }
}

eventChild:

<template>
    <lightning-button
    variant="brand"
    label="Submitchild"
    onclick={handleClick}>
    </lightning-button> 
    <div onnotify={handleNotify1}>
    <c-eventgrandchild onnotify={handleNotify}></c-eventgrandchild>
</div>
    </template>

Javascript file:

import { LightningElement } from 'lwc';

export default class EventChild extends LightningElement {
    handleClick() {
        alert('alert from child');
    }
    handleNotify(){
        alert("received event from grand child");
    }
    handleNotify1(){
        alert("received event from grand child through bubble"); 
    }
}

eventgrandchild:

<template>
    <lightning-button
    variant="brand"
    label="Submitgrandchild"
    onclick={handleClick}>
    </lightning-button>    
</template>

Javascript file:

import { LightningElement } from 'lwc';

export default class Eventgrandchild extends LightningElement {
    handleClick() {
        alert('alert from grand child1');
        this.dispatchEvent(
            // Default values for bubbles and composed are false.
            new CustomEvent('notify',{ bubbles: true })
        );
    }
}

Question:

  1. What is the correct way to fire an event from grand child which my owner(in this case eventParent) needs to receive and react accordingly?
  2. According to documentation they say use capture and bubbles false which is the most recommended,if i use that the event will never reach the parent. Are we expected to catch this event in event child component and fire an event again which will be handled by the parent component?
    Just trying to understand the best practices around events.

Update based on Jayant's Answer:
Based on documentation from salesforce it seems the way to do it is to pass the event upward in the hierarchy

Events Up, Properties Down

In a complex component (one that contains several parent and child
components) we recommend you propagate the event up through the
component hierarchy, so parent components can respond to child events.
If you have other child components (not the one firing the event) you
can pass a property down to those children in response to the event.

If i have 4 or 5 level hierarchy i need to fire 4 events to reach the top which seems a bit of overkill. Is this the only way to do it or can we use capture and bubbles true and push the event up?

Best Answer

There is a good example of this topic on Handle Events in Lightning Web Components trailhead which discusses the same use case as you have here (and answers both your questions).

The idea is to chain the events up the hierarchy. So basically you will need to handle the event being propagated in every component and then pass it on up in the hierarhcy.

Below excerpt and the image from the linked trailhead module describes this in detail :

Events Up, Properties Down

In a complex component (one that contains several parent and child components) we recommend you propagate the event up through the component hierarchy, so parent components can respond to child events. If you have other child components (not the one firing the event) you can pass a property down to those children in response to the event.

Image Courtesy: Trailhead

(Image Source: Handle Events in Lightning Web Components)

Update : Passing event from grand-child to grand-parent

Lets say we have a LWC component structure as follows.

Component Structure

We can pass event values between grand-child and grand-parent or the top most root component as follows.

Use bubbles : true to pass values up the component hierarchy. And use composed : true if you want to expose the event outside the shadow root.

grandChild.js

const sampleEvent = new CustomEvent('search', { bubbles : true, detail: { foo : 'bar' }, composed : true });
this.dispatchEvent(sampleEvent);

Note: If an event uses this configuration bubbles:true & composed:true, the event type becomes part of the component’s public API. It also forces the consuming component and all of its ancestors to include the event as part of their APIs.

This way, we don't have to handle this event in the parent component , Instead in grand parent we can handle it as follows

grandParent.html

<c-parent onsearch={handleSearch}></c-parent>

grandParent.js

handleSearch = (event) => {
   console.log(event.detail);
}

For more details , refer - LWC Events Propagation