0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

親子コンポーネント関係

Posted at

親子コンポーネント関係についてまとめ

練習内容のアウトプット
個人的な解釈とか考え方もあるかも

目的

・イベント処理を 子コンポーネント ⇔ 親コンポーネント 間でやり取りできるようにする
 

親側 html
<template>
   <template for:each={todoList} for:item="todo" for:index="i">
       <c-todo-item
           key={todo.id}
           item={todo}          <!-- todoオブジェクトを渡す -->
           username={userName}  <!-- 親のuserName変数を渡す -->
           index={i}            <!-- ループの番号を渡す -->
           ondeleteitem={handleDelete}> <!-- 子がイベント発火したらhandleDeleteを実行 -->
       </c-todo-item>
   </template>
</template>
親側 js
import { LightningElement, track } from 'lwc';

export default class TodoApp extends LightningElement {
    @track todoList = [
        { id: 1, name: '掃除' },
        { id: 2, name: '買い物' }
    ];

    userName = '太郎';

    handleDelete(event) {
        const idToDelete = event.detail; 
        this.todoList = this.todoList.filter(todo => todo.id !== idToDelete);
    }
}
子側 html
<template>
    <div>
        {index}番目: {item.name}担当: {username}
        <button onclick={deleteItem}>削除</button>
    </div>
</template>
子側 js
import { LightningElement, api } from 'lwc';

export default class TodoItem extends LightningElement {
    @api item;      // 親からの todo
    @api username;  // 親からの userName
    @api index;     // 親からのループ番号

    deleteItem() {
        this.dispatchEvent(new CustomEvent('deleteitem', {
            detail: this.item.id
        }));
    }
}

まずコードを読むときの流れとして親 → 子 → 親 で読むようになる
親コンポーネントはApp とか List みたいに「全体を管理する名前」が付く名称が多い
子コンポーネントはItem とか Row みたいに「個別要素っぽい名前」が付く名称が多い

 

①c-todo-item この記述で親から子に渡す記述を行う

この c-todo-item と書いた瞬間に書いたコンポーネントが親になる
ondeleteitem={handleDelete} この記述は関数を子に渡しているわけじゃなく、イベント名と親の処理を結びつけているだけの記述という認識

親側のhtml 該当記述箇所
        <c-todo-item
            key={todo.id}
            item={todo}          <!-- todoオブジェクトを渡す -->
            username={userName}  <!-- 親のuserName変数を渡す -->
            index={i}            <!-- ループの番号を渡す -->
            ondeleteitem={handleDelete}> <!-- 子がイベント発火したらhandleDeleteを実行 -->
        </c-todo-item>

 
 

②子側で @api の記述で親から受け取る

受け取りたいものをそれぞれ子のjs側に記述する必要がある

子側のjs 該当記述箇所
    @api item;      // 親からの todo
    @api username;  // 親からの userName
    @api index;     // 親からのループ番号

上記の記述で親から値を取得しているので子側のHTMLの記述でitem,username,index等の値を画面表示できる
ここまではまだ、イベントは発火していない状態で、値をjs側で保持しているだけの状態
下記記述部分が子側のHTML該当箇所

子側のhtml 該当記述箇所
        {index}番目: {item.name}担当: {username}
        <button onclick={deleteItem}>削除</button>

削除ボタンを押下するとdeleteItemの関数内の this.dispatchEventが発火する
deleteItem関数を子側のjsで記述している

子側のjs 該当記述箇所
    deleteItem() {
        this.dispatchEvent(new CustomEvent('deleteitem', {
            detail: this.item.id
        }));
    }

this.dispatchEvent この記述はボタン押下した時に、この中の処理の内容を親側に送る為の記述となる

new CustomEvent('deleteitem この記述はカスタムイベントの新規作成の記述でイベント名はdeleteitemで作成する記述 (親側でondeleteitemと記述してイベントとして使えるようになる)

detail: this.item.id この記述のdetail は イベントオブジェクトに入れられる「入れ物」 です。実際にはオブジェクトでも何でも渡せる。detail は「追加情報の箱」で、その中身は 開発者が決められる。今回はIDを入れて親コンポーネントに渡すように記述しています。

 

③親側で子から値を受け取って処理(イベント伝播)

親側のhtml 該当記述箇所
           ondeleteitem={handleDelete}> <!-- 子がイベント発火したらhandleDeleteを実行 -->

子から受け取った値(detail: this.item.id)を元にhandleDeleteの関数を実行して処理を行う
子は dispatchEvent(new CustomEvent('deleteitem', { detail: id })) で「削除して!」というイベントを親に通知。親は ondeleteitem={handleDelete} でそれを受け取って処理。これが「イベント伝播」で、LWCの 親子連携の基本の仕組み

下記記述で子から受けとったdetailの値を変数に入れて表示を制限する記述となる
const idToDelete = event.detail; の記述について
event はフレームワークが「自動で渡してくれるオブジェクト」
detail は「自分が箱に入れた中身」
だから event.detail で受け取るのは自然な流れとなる

親側のjs 該当記述箇所
        const idToDelete = event.detail; 
        this.todoList = this.todoList.filter(todo => todo.id !== idToDelete);

 
 

全体の流れ

1,親が todoList を持っている(例:[{id: 1, name: "掃除"}, {id: 2, name: "勉強"}])。
2,親は繰り返し処理で を子に渡す。
3,子は @api item; を使って todo データを受け取る。
@api item;)= 値を受け取って箱に入れておく段階。まだ何も起きてない。
4,子で「削除」ボタンをクリックすると dispatchEvent(new CustomEvent('deleteitem', {detail: this.item.id})) が走る。
(ボタン押下 → dispatchEvent)= 初めて親に通知が飛ぶ。
5,親が ondeleteitem={handleDelete} で受け取り、event.detail から id を取得。
6,親の todoList を filter で更新 → 再描画される。

補足

親と子のデータのやり取りについての補足

できること
・detail にデータを入れて渡す(数値・文字列・オブジェクトなんでも)
・bubbles: true を指定すると 親のさらに親 まで伝えることもできる
・composed: true を指定すると Shadow DOM を超えて 上位まで伝える
例:
new CustomEvent('deleteitem', {
detail: { id: 3, name: '掃除' },
bubbles: true,
composed: true
});

できないこと
親の関数や変数に 直接アクセスすること
(これができちゃうと、親と子の独立性がなくなって設計が壊れるから)

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?