1
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?

[Salesforce] LWCデコレータ(@api / @track / @wire)とはなんぞや

Posted at

1. LWC デコレータとは?

LWC のデコレータとは、親子関係にあるコンポーネント間でのイベント伝達、値の受け渡し、リレンダー、Apex処理の呼び出しを行う。

代表的なデコレータは以下の 3 つ

  • @api : 親コンポーネントとのインターフェース
  • @track : オブジェクトや配列のリアクティブ管理
  • @wire : レコードへのアクセスやサーバーサイド(Apex)とのデータ連携

2. @api

🔹 特徴

  • @api は、親 → 子の一方向通信を実現するための「公開インターフェース」
    • 「外部(親)からアクセスしてOKです」という公開マーク
      →外部に公開する側(= 子)にだけ必要
  • 一方向通信(親 → 子)専用

@api の基本ルール

  • @api子コンポーネントにだけ必要
    • 親側には書かない。@api がついていないプロパティやメソッドは、親からアクセスできない(隠蔽される)。
  • 子 → 親へ値を戻したいときは カスタムイベント (dispatchEvent) を使う。

🔹 親 → 子 → 親 へ値を戻したい場合

  • @api は親→子の一方向通信なので、逆方向には使えない
  • **子 → 親に値を戻したい場合は、カスタムイベント(dispatchEvent)を使用する!

⚙️ どういうときに使う?

  • 親コンポーネントから 値を渡すメソッドを呼ぶ の2つの用途で使われる。
使いみち
親 → 子にデータを渡す 親で入力された値を子に表示させる
親 → 子のメソッドを呼ぶ 親から子の初期化・リセット・開閉制御など

🔹 例:親 → 子で値を渡す

ChildComponent.js

import { LightningElement, api } from 'lwc';

export default class ChildComponent extends LightningElement {
    @api message;
}

ParentComponent.html

<template>
    <c-child-component message="Hello Child!"></c-child-component>
</template>

🔹 例:親 → 子のメソッドを呼ぶ

ChildComponent.js

import { LightningElement, api } from 'lwc';

export default class ChildComponent extends LightningElement {
    @api
    sayHello() {
        console.log('Hello from Child!');
    }
}

ParentComponent.js

import { LightningElement } from 'lwc';

export default class ParentComponent extends LightningElement {
    handleClick() {
        this.template.querySelector('c-child-component').sayHello();
    }
}

ParentComponent.html

<template>
    <lightning-button label="Call Child" onclick={handleClick}></lightning-button>
    <c-child-component></c-child-component>
</template>

3. @track

🔹 特徴

  • @track はオブジェクトや配列の内部の変更をリアクティブに反映するためのデコレータ
  • LWC はプリミティブ型(文字列・数値・真偽値など)は自動でリアクティブ化されるので、@track は不要。
  • 逆にオブジェクトや配列などの中身を変えるだけの場合は @track が必要。

✅ どういう時に使えばええの?

状況 必要?
プリミティブ型(文字列・数値・true/false) ❌ 不要
オブジェクト・配列の中身だけを変える ✅ 必要
オブジェクト・配列を丸ごと新しく作り直して代入する ❌ 不要

✅ 必要になるケース

🔹 例)オブジェクトの中身だけを変えたい

import { LightningElement, track } from 'lwc';

export default class ExampleTrack extends LightningElement {
  @track person = { name: 'Taro', age: 30 };

  changeName() {
    this.person.name = 'Jiro'; // @track がないと画面に反映されない!
  }
}

🔹 例)配列に要素を追加する

import { LightningElement, track } from 'lwc';

export default class ExampleTrackArray extends LightningElement {
  @track fruits = ['Apple'];

  addFruit() {
    this.fruits.push('Orange'); // @track がないと画面に反映されない!
  }
}}

✅ 不要になるケース

🔹 オブジェクト or 配列を丸ごと置き換える

import { LightningElement } from 'lwc';

export default class ExampleNoTrack extends LightningElement {
  person = { name: 'Taro' };

  changeName() {
    this.person = { ...this.person, name: 'Jiro' }; // 新しいオブジェクトで置き換え → OK!
  }
}

or

import { LightningElement } from 'lwc';

export default class ExampleNoTrackArray extends LightningElement {
  fruits = ['Apple'];

  addFruit() {
    this.fruits = [...this.fruits, 'Orange']; // 新しい配列を代入 → OK!
  }
}

🔹プリミティブ型

import { LightningElement } from 'lwc';

export default class ExamplePrimitive extends LightningElement {
  name = 'Taro';

  changeName() {
    this.name = 'Jiro'; // 文字列だけなので @track は不要!
  }
}

⚠️ @track の注意点

  • 最近の LWC では @track を使用するよりも「オブジェクトや配列を丸ごと新しいものに置き換える」書き方が主流らしい?
  • 理由 = バグりにくい / 保守しやすい

🔑 ポイント

中身だけ変える → @track
丸ごと代入できる → @track いらない
👉 迷ったら 「新しく作り直して代入する」 で OK!


4. @wire

🔹 特徴

  • LWC コンポーネントと Apex(または LDS)をつなぐ自動配線
  • @wire は**「データ取得だけ」ではなく「データの自動更新」** にも対応できる。

✅ 使い方3パターン

使い方 おすすめシーン
@wire プロパティ形式 データを取って画面に出すだけ
@wire 関数形式 ローディング表示や追加処理を入れたい
Imperative Apex 呼び出し ボタン押下などユーザー操作で任意タイミング

✅ まずは Apex 側の準備

必ず@AuraEnabled(cacheable=true) を付ける。

public with sharing class ContactController {
    @AuraEnabled(cacheable=true)
    public static List<Contact> getContacts() {
        return [SELECT Id, Name, Email FROM Contact LIMIT 10];
    }
}

🔹 例1: @wire プロパティ形式

import { LightningElement, wire } from 'lwc';
import getContacts from '@salesforce/apex/ContactController.getContacts';

export default class ContactList extends LightningElement {
  @wire(getContacts) contacts;
}
<template>
  <template if:true={contacts.data}>
    <template for:each={contacts.data} for:item="contact">
      <p key={contact.Id}>{contact.Name}</p>
    </template>
  </template>

  <template if:true={contacts.error}>
    <p>エラー: {contacts.error.message}</p>
  </template>
</template>

🔑 ポイント
• contacts は { data, error } を自動で持つ
• 成功すれば contacts.data、失敗すれば contacts.error
• 加工できないので、表示だけの用途に最適


🔹 例2: @wire 関数形式

import { LightningElement, wire } from 'lwc';
import getContacts from '@salesforce/apex/ContactController.getContacts';

export default class ContactListFunction extends LightningElement {
  contacts;
  error;
  isLoading = true;

  @wire(getContacts)
  wiredContacts({ data, error }) {
    this.isLoading = false;
    
    if (data) {
      this.contacts = data;
      this.error = undefined;
    } else if (error) {
      this.error = error;
      this.contacts = undefined;
    }
  }
}
<template>
  <template if:true={isLoading}>
    <p>Loading...</p>
  </template>

  <template if:true={contacts}>
    <template for:each={contacts} for:item="contact">
      <p key={contact.Id}>{contact.Name}</p>
    </template>
  </template>

  <template if:true={error}>
    <p>エラー: {error.message}</p>
  </template>
</template>

🔑 ポイント
• wiredContacts({ data, error }) の形で結果を分解

🔹 例3: Imperative Apex (明示的呼び出し)

import { LightningElement } from 'lwc';
import getContacts from '@salesforce/apex/ContactController.getContacts';

export default class ImperativeExample extends LightningElement {
  contacts;
  error;

  handleClick() {
    getContacts()
      .then(result => {
        this.contacts = result;
        this.error = undefined;
      })
      .catch(error => {
        this.error = error;
        this.contacts = undefined;
      });
  }
}
<template>
  <lightning-button label="取引先責任者を取得" onclick={handleClick}></lightning-button>

  <template if:true={contacts}>
    <template for:each={contacts} for:item="contact">
      <p key={contact.Id}>{contact.Name}</p>
    </template>
  </template>

  <template if:true={error}>
    <p>エラー: {error.message}</p>
  </template>
</template>

🔑 ポイント
• getContacts() を then で受け取る
• catch でエラーをハンドリング
• 任意のタイミングで呼べるのが強み


✅ そもそも @AuraEnabled とは?

• Apex メソッドを LWC や Aura コンポーネントから呼び出せるようにする ためのアノテーション。(これがないと JavaScript から呼べない。)

✅ cacheable=true の意味

@wire は 非同期通信でデータを取るときにキャッシュ可能(= データの再利用が可能) なメソッドじゃないと使えない。
@wire は リアクティブな自動更新 を担うので、Salesforce の LDS(Lightning Data Service)と同じく、読取専用 & キャッシュ前提で動く。

✅ なぜ必須なのか

@wire は 「読取専用」 だから、取得して終わりなので、データ更新系(INSERT, UPDATE, DELETE)は使えない。→ cacheable=true を指定して、「これは読取専用だよ!キャッシュして良いよ!」 と明示する必要がある。

1
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
1
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?