Lightning データサービスの使用とコンポーネント間の通信

パート 1: Lightning データサービスを使用する

[Property (物件)] レコードページで、物件の価格を編集します。たとえば、$200,000 増やしてみます。[Save (保存)] をクリックします。価格変更時にコンポーネントは再読込されません。[Property (物件)] レコードページの価格が変更されたら、類似物件のリストを自動的に更新するにはどうすればよいでしょうか?

  1. 開発者コンソールで、SimilarProperties コンポーネントマークアップを開きます。
  2. 次の属性を追加します。
  3. <aura:attribute name="property" type="Property__c"/>
    
  4. force:recordData オブジェクトをコンポーネントの最後の aura:handler の後に追加します。
  5. <force:recordData aura:id="propertyService"
        recordId="{!v.recordId}"
        targetRecord="{!v.property}"
        recordUpdated="{!c.doInit}"
        layoutType="FULL"/>
    

    force:recordData は、recordId 属性で指定されたレコードを自動的に取得し、そのデータを targetRecord 属性で定義された <aura:attribute> に保存します。続いて force:recordData は、ページの他のコンポーネントがそのレコードに行った変更のリスンを開始し、変更を検出した時点で、recordUpdated 属性で定義された JavaScript 関数を起動します。

  6. ファイルを保存して、[Property (物件)] レコードページを更新します。
  7. 物件の価格を編集すると、コンポーネントが新しい検索を実行します。
  8. [Similar Properties (類似物件)] リストのレコードを編集し、価格を $10,000 以上増やします。コンポーネントは更新されません。

パート 2: カスタム Aura イベントを使用する

次は、Aura イベントを追加して、レコードが更新されたことをページの他のコンポーネントに知らせる必要があります。Aura イベントによって、他のコンポーネントがリスン可能なイベントが起動されます。そして実際、この時点で SimilarProperties コンポーネントにイベントをリスンさせ、ページにあるコンポーネントの複数のインスタンスがまとめて更新されるようにします。

  1. 開発者コンソールで、[File (ファイル)] > [New (新規)] > [Lightning Event (Lightning イベント)] をクリックします。
  2. イベントに「recordUpdated」という名前を付けます。
  3. [Submit (実行)] をクリックします。
  4. ファイルを閉じます。
  5. SimilarProperties.cmp に切り替えます。
  6. 次のコードを既存の aura:handler の後の新しい行に追加します。
  7. <aura:handler event="c:recordUpdated" action="{!c.doInit}"/>
  8. ファイルを保存します。
  9. SimilarProperty.cmp に切り替えます。
  10. aura:attribute の後に新しい行に、次のコードを追加します。
  11. <aura:registerEvent name="recordUpdated" type="c:recordUpdated"/>
  12. ファイルを保存し、SimilarPropertyController.js に切り替えます。
  13. 次のコードを handleSuccess 関数の toastEvent.fire() の直後に追加します。
  14. var recUpdate = $A.get("e.c:recordUpdated");
    recUpdate.fire();
  15. ファイルを保存して、[Property (物件)] ページを更新します。
  16. [Similar Properties (類似物件)] リストのレコードを編集します。
  17. コンポーネントが更新されます。

パート 3: デザインパラメータを使用する

システム管理者に気に入ってもらえるように、ページにコンポーネントを追加するときに変更可能なパラメータを公開しましょう。システム管理者が検索条件を指定したり、価格を検索するときに範囲を指定したりできるようにします。また、機能しないページに誤ってコンポーネントを追加することがないようにします。たとえば、Similar Properties コンポーネントを [Contact (取引先責任者)] レコードページに追加しても意味がありません。デザインファイルを使用すると、コンポーネントを使用できるオブジェクト種別を指定できます。たとえば、[Contact (取引先責任者)] レコードページでは、Lightning アプリケーションビルダーの使用可能なコンポーネントリストにこのコンポーネントが表示されません。

  1. 2 つの新しい属性を SimilarProperties.cmp に追加します。
  2. <aura:attribute name="searchCriteria" type="String" default="Price"/>
    <aura:attribute name="priceRange" type="String" default="100000"/>
    
  3. lightning:card タグのタイトルを {! 'Similar Properties by ' + v.searchCriteria} に更新します。次のようになります。
  4. <lightning:card iconName="custom:custom85" title="{! 'Similar Properties by ' + v.searchCriteria}">
  5. SimilarPropertiesController に切り替えます。
  6. アクションを var action = component.get("c.getSimilarProperties"); に更新します。
  7. アクションのパラメータを次のコードに更新します。
  8. action.setParams({
        recordId: component.get("v.recordId"),
        beds: component.get("v.property.fields.Beds__c.value"),
        price: component.get("v.property.fields.Price__c.value"),
        searchCriteria: component.get("v.searchCriteria"),
        priceRange: parseInt(component.get("v.priceRange"), 10)
    });
    
  9. 開発者コンソールで、[File (ファイル)] > [Open Resource (リソースを開く)] を選択して、MyPropertyController をクリックします。
  10. FindProperties メソッドを削除し、getSimilarProperties メソッドを一致するように更新します。
  11. @AuraEnabled
    public static List<Property__c> getSimilarProperties (Id recordId, String searchCriteria, Decimal beds, Decimal price, Decimal priceRange ) {
        if (searchCriteria == 'Bedrooms') {
            return [
                SELECT Id, Name, Beds__c, Baths__c, Price__c, Broker__c, Status__c, Thumbnail__c
                FROM Property__c WHERE Id != :recordId AND Beds__c = :beds
            ];
        } else {
            Decimal range;
                if (priceRange == null) {
                    range = 100000;
                } else {
                    range = priceRange;
                }
                return [
                    SELECT Id, Name, Beds__c, Baths__c, Price__c, Broker__c, Status__c, Thumbnail__c
                    FROM Property__c WHERE Id != :recordId AND Price__c > :price - range AND Price__c < :price + range
                ];
        }
    }
    
  12. ファイルを保存します。
  13. [Property (物件)] レコードページを更新します。現在のレコードの ID、寝室数、および価格が渡されて、物件が取得されるようになりました。
  14. 開発者コンソールで、SimilarProperties.cmp ファイルに切り替えます。
  15. [Design (デザイン)] タイルをクリックしてデザインファイルをコンポーネントバンドルに追加します。
  16. 次のコードを design:component タグの間のデザインファイルに追加します。
  17. <design:attribute name="searchCriteria" label="Search By" datasource="Bedrooms, Price, Sq Foot" default="Price" description="Search for similar houses based on what criteria?"/>
    <design:attribute name="priceRange" label="Price Range" default="100000" description="When searching by Price, search using the price plus or minus this amount"/>
    

    デザイン属性は、アプリケーションビルダーに公開されるパラメータです。デザイン属性ごとに、コンポーネントにそのデザイン属性とまったく同じ名前が付いた、対応する aura 属性が必要です。公開するデザインパラメータには、テキスト入力項目と選択リストのいずれかを使用できます。選択リストのパラメータには、<design:attribute name="searchCriteria"> のように、選択肢のカンマ区切りリストが指定された datasource 属性が必要です。priceRange の属性も追加されています。この属性は、Apex クラスでこの値の前後の物件を検索するために使用します。

  18. [Property (物件)] レコードページに切り替えます。
  19. [Setup (設定)] アイコンをクリックして、[Edit Page (編集ページ)] を選択します。
  20. 次の手順は省略可能です。
    1. ページの SimilarProperties コンポーネントをクリックし、削除キーをタップ (または [X] をクリック) してページからコンポーネントを削除します。
    2. Lightning アプリケーションビルダーで [Save (保存)] ボタンをクリックします。
    3. 開発者コンソールに戻り、次のコードを Design ファイルに追加します。
    4. <sfdc:objects>
          <sfdc:object>Property__c</sfdc:object>
      </sfdc:objects>
      

      <sfdc:objects> リストは、コンポーネントを使用できるオブジェクトページの種別を定義します。Property__c ページ以外でこのコンポーネントを使用する場合は、新しい <sfdc:object> をリストに追加するだけです。

    5. ファイルを保存します。
  21. Similar Properties コンポーネントの 2 つのインスタンスをページにドラッグします。一方のインスタンスを [Bedrooms (寝室)]、もう一方を [Price (価格)] に設定します。
  22. ページを保存して、[Property (物件)] レコードに戻ります。

パート 4: Lightning アプリケーションビルダーに表示されるカスタムアイコンを追加する

Aura コンポーネントを作成するときは、コンポーネントのアイコンを作成して、Lightning アプリケーションビルダーのコンポーネント名の横に表示することを選択できます。デフォルトでは、どのカスタムコンポーネントにも青い四角に白い稲妻がアイコンとして設定されます。では、このコンポーネントに独自のアイコンを設定してみましょう。

  1. 開発者コンソールの SimilarProperties.cmp タブに切り替え、ウィンドウの右側にある [SVG] タイルをクリックします。
  2. (参考情報) 次の手順は、SLDS サイトから SVG アイコンをダウンロードし、コンポーネントに追加する方法を示します。この手順は参考情報であり、このプロジェクトで実行する必要はありません。
    1. 新しいブラウザタブで、もう一度 SLDS サイトを開きます。
    2. このサイトの [Icons (アイコン)] セクションに移動します。
    3. スクロールダウンし、アイコンの [Custom (カスタム)] セクションで custom85 を見つけます。
    4. 通常は、ナビゲーションパネルの [Downloads (ダウンロード)] リンクをクリックし、[Icons (アイコン)] セクションまでスクロールダウンして [Downloads Icons (アイコンをダウンロード)] ボタンをクリックします。
    5. ダウンロードした zip ファイルに移動して解凍したら、フォルダを開いて [custom] フォルダを開きます。
    6. custom85.svg ファイルを見つけて、テキストエディタで開きます。
    7. [SVG] から <path> タグをコピーします。
    8. 開発者コンソールで、SimilarProperties.svg に切り替えます。
    9. 2 つ目の <path> タグを、コピーしたタグに置き換えます。
    10. 貼り付けた <path> の先頭の「d」属性の前に、fill="#fff" を追加します。
    11. <svg> タグの width="120px" height="120px" viewBox="0 0 120 120" を次のコードに置き換えます。
    12. width="100px" height="100px" viewBox="0 0 100 100"

    13. 最初の <path> の塗りつぶしを #F26891 に変更します。
  3. すべてを選択し、開発者コンソールの .svg ファイルを次のコードに置き換えます。
  4. <?xml version="1.0" encoding="UTF-8" standalone="no"?>
    <svg width="100px" height="100px" viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
        <g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
            <path d="M120,108 C120,114.6 114.6,120 108,120 L12,120 C5.4,120 0,114.6 0,108 L0,12 C0,5.4 5.4,0 12,0 L108,0 C114.6,0 120,5.4 120,12 L120,108 L120,108 Z" id="Shape" fill="#2A739E"/>
            <path fill="#FFF" d="m78 24h-50v-2c0-1.1-0.9-2-2-2h-4c-1.1 0-2 0.9-2 2v56c0 1.1 0.9 2 2 2h4c1.1 0 2-0.9 2-2v-46h50c1.1 0 2-0.9 2-2v-4c0-1.1-0.9-2-2-2z m-4 14h-34c-3.3 0-6 2.7-6 6v22c0 3.3 2.7 6 6 6h34c3.3 0 6-2.7 6-6v-22c0-3.3-2.7-6-6-6z m-5.5 17h-2.5v10c0 0.6-0.4 1-1 1h-4c-0.6 0-1-0.4-1-1v-6c0-0.6-0.4-1-1-1h-4c-0.6 0-1 0.4-1 1v6c0 0.6-0.4 1-1 1h-4c-0.6 0-1-0.4-1-1v-10h-2.5c-0.5 0-0.7-0.6-0.3-0.9l11.2-10.9c0.4-0.3 0.9-0.3 1.3 0l11.2 10.9c0.3 0.3 0.1 0.9-0.4 0.9z">
            </path>
        </g>
    </svg>
    
  5. ファイルを保存します。
  6. Lightning アプリケーションビルダーに切り替え、コンポーネントのリストの上部にある [Refresh (更新)] ボタンをクリックします。

パート 6: スピナーを表示/非表示にする

ここまでよく頑張りました! けれども、コンポーネントが最初にページに読み込まれるとき、ユーザとしてちょっとした違和感を覚えます。最初にカードのタイトルバーしか示されず、しばらくしてからコンテンツが表示されるからでしょうか。ネットワークに問題があったらどうなるか想像してください。このためユーザが、コンテンツがあることに気付かなかったり、最新のコンテンツが読み込まれたのかどうかわからなかったりする可能性があります。Salesforce ではスピナーを使用して、ネットワークアクティビティが進行中であることを示します。ここで、データを取得中または更新中であることを示すスピナーを追加してみましょう。

  1. 開発者コンソールで、SimilarProperties コンポーネントに切り替えます。
  2. マークアップの最後にある </lightning:card> 終了タグのに次のコードを追加します。
  3. <lightning:spinner aura:id="spinner" variant="brand" size="large"/>
  4. ファイルを保存します。
  5. class="slds-is-relative"<lightning:card> タグに追加して、次のようにします。
  6. <lightning:card iconName="custom:custom85" title="{! 'Similar Properties by ' + v.searchCriteria}" class="slds-is-relative">
    
  7. ファイルを保存します。
  8. [STYLE (スタイル)] をクリックして、カスタム CSS ファイルを SimilarProperties コンポーネントに追加し、デフォルトの内容を次のコードに置き換えます。
  9. .THIS {
        min-height: 13rem;
    }
    

    Lightning コンポーネントにカスタム CSS を使用すると、そのコンポーネントをラップする HTML 要素に .THIS クラスが自動的に適用されます。この場合、それは <lightning:card> です。min-height 属性は、コンポーネントの高さの最小値を指定します。ここでは、1 つの物件レコードの高さに設定されています。

  10. ファイルを保存します。
  11. [Property (物件)] レコードページを再読み込みします。何か違っていますか?
  12. 開発者コンソールで、[CONTROLLER (コントローラ)] をクリックして、SimilarPropertiesController を開きます。
  13. 次のコードを doInit 関数の先頭の var action 宣言の前に追加します。
  14. var spinner = component.find("spinner");
    $A.util.removeClass(spinner, "slds-hide");
    
  15. 次のコードをアクションのコールバックの最後に追加します。
  16. $A.util.addClass(spinner, "slds-hide");
    

    コントローラに 3 行のコードが追加されました。1 行目の var spinner = component.find("spinner"); は、スピナーへの変数参照を作成します。component.find() メソッドは、マークアップ内の要素を見つけるために使用します。<lightning:spinner> を作成したときに、「スピナー」の aura:id にこのメソッドを割り当てています。ですから、マークアップに移動して、スピナーの aura:id が設定されているものを探すことにします。


    $A.util.removeClass(spinner, "slds-hide"); はフレームワークに ($A を覚えていますか?)、removeClass() ユーティリティメソッドを使用して、スピナーから slds-hide CSS クラスを削除するよう指示します。slds-hide クラスは、その名が示すとおり、そのクラスに配置されている要素をすべて非表示にします。したがって、slds-hide クラスが削除されると、コンポーネントの読み込み中は常にスピナーが表示されるようになります。アクションのコールバックに、$A.util.addClass(spinner, "slds-hide"); が追加されています。これは単に slds-hide クラスをスピナーに追加し直すものです。


  17. ファイルを保存して、[Property (物件)] レコードページを更新します。
  18. レコードを変更して、スピナーを確認しましょう。

これで、データを読み込んでいる間にのみスピナーが表示され、データが取り込まれたら画面から消えるようになります。

パート 7: 条件付きでコンテンツを表示する

  1. 開発者コンソールで、SimilarProperties コンポーネントマークアップに切り替えます。
  2. <ul> の内容を次のコードに置き換えます。
  3. <aura:if isTrue="{!v.similarProperties.length > 0}">
        <aura:iteration items="{!v.similarProperties}" var="item">
            <li class="slds-list__item">
                <c:SimilarProperty property="{!item}"/>
            </li>
        </aura:iteration>
        <aura:set attribute="else">
            <li class="slds-list__item">
                <h3 class="slds-text-small slds-text-color_error">No similar properties found.</h3>
            </li>
        </aura:set>
    </aura:if>
    
  4. ファイルを保存して、ページを更新します。

[Property (物件)] レコードの価格を、$200,000 など、類似物件のないものに変更し、コンポーネントの空の状態を確認します。

問題がある場合は、コードを次のコードと比較して確認してください。

SimilarProperties.cmp

<aura:component controller="MyPropertyController" implements="flexipage:availableForRecordHome,force:hasRecordId" access="global">
    <aura:attribute name="recordId" type="Id"/>
    <aura:attribute name="similarProperties" type="Object[]"/>
    <aura:attribute name="property" type="Property__c"/>
    <aura:attribute name="searchCriteria" type="String" default="Price"/>
    <aura:attribute name="priceRange" type="String" default="100000"/>
    <aura:handler event="c:RecordUpdated" action="{!c.doInit}"/>
    <aura:handler name="init" value="{! this}" action="{!c.doInit}"/>
    <force:recordData aura:id="propertyService"
        recordId="{!v.recordId}"
        targetRecord="{!v.property}"
        recordUpdated="{!c.doInit}"
        layoutType="FULL"/>
    <lightning:card iconName="custom:custom85" title="{! 'Similar Properties by ' + v.searchCriteria}" class="slds-is-relative">
        <div class="slds-p-left_medium slds-p-right_medium">
            <ul class="slds-list_vertical slds-has-dividers_top-space">
                <aura:if isTrue="{!v.similarProperties.length &gt; 0}">
                    <aura:iteration items="{!v.similarProperties}" var="item">
                        <li class="slds-list__item">
                            <c:SimilarProperty property="{!item}"/>
                        </li>
                    </aura:iteration>
                    <aura:set attribute="else">
                        <li class="slds-list__item">
                            <h3 class="slds-text-small slds-text-color_error">No similar properties found.</h3>
                        </li>
                    </aura:set>
                </aura:if>
            </ul>
        </div>
        <lightning:spinner aura:id="spinner" variant="brand" size="large"/>
    </lightning:card>
</aura:component>

SimilarPropertiesController.js

({
    doInit : function(component, event, helper) {
        var spinner = component.find("spinner");
        $A.util.removeClass(spinner, "slds-hide");
        var action = component.get("c.getSimilarProperties");
        action.setParams({
            recordId: component.get("v.recordId"),
            beds: component.get("v.property.fields.Beds__c.value"),
            price: component.get("v.property.fields.Price__c.value"),
            searchCriteria: component.get("v.searchCriteria"),
            priceRange: parseInt(component.get("v.priceRange"), 10)
        });
        action.setCallback(this, function(response){
            var similarProperties = response.getReturnValue();
            component.set("v.similarProperties", similarProperties);
            console.log("f: ", component.get("v.similarProperties"));
            $A.util.addClass(spinner, "slds-hide");
        });
        $A.enqueueAction(action);
    }
})

SimilarProperties.css

.THIS {
    min-height: 13rem;
}

SimilarProperties.design

<design:component>
    <sfdc:objects>
        <sfdc:object>Property__c</sfdc:object>
    </sfdc:objects>
    <design:attribute name="searchCriteria" label="Search By" datasource="Bedrooms, Price, Sq Foot" default="Price" description="Search for similar houses based on what criteria?"/>
    <design:attribute name="priceRange" label="Price Range" default="100000" description="When searching by Price, search using the price plus or minus this amount"/>
</design:component>

SimilarProperty.cmp

<aura:component>
    <aura:attribute name="property" type="Property__c"/>
    <aura:registerEvent name="recordUpdated" type="c:RecordUpdated"/>
    <lightning:recordViewForm aura:id="viewForm" recordId="{!v.property.Id}" objectApiName="Property__c">
        <div class="slds-media">
            <div class="slds-media__figure">
                <img src="{!v.property.Thumbnail__c}" class="slds-avatar_large slds-avatar_circle" alt="{!v.targetFields.Title_c}"/>
            </div>
            <div class="slds-media__body">
                <lightning:layout class="slds-hint-parent">
                    <a onclick="{!c.navToRecord}">
                        <h3 class="slds-text-heading_small slds-m-bottom_xx-small">{!v.property.Name}</h3>
                    </a>
                    <lightning:buttonIcon iconName="utility:edit" class="slds-col_bump-left" iconClass="slds-button__icon_hint" variant="bare" alternativeText="Edit Record" onclick="{!c.editRecord}"/>
                </lightning:layout>
                <lightning:layout multipleRows="true">
                    <lightning:layoutItem size="6">
                        <lightning:outputField fieldName="Beds__c"/>
                    </lightning:layoutItem>
                    <lightning:layoutItem size="6">
                        <lightning:outputField fieldName="Baths__c"/>
                    </lightning:layoutItem>
                    <lightning:layoutItem size="6">
                        <lightning:outputField fieldName="Price__c"/>
                    </lightning:layoutItem>
                    <lightning:layoutItem size="6">
                        <lightning:outputField fieldName="Status__c"/>
                    </lightning:layoutItem>
                </lightning:layout>
            </div>
        </div>
    </lightning:recordViewForm>
    <lightning:recordEditForm aura:id="editForm" recordId="{!v.property.Id}" objectApiName="Property__c" class="slds-hide" onsuccess="{!c.handleSuccess}">
        <div class="slds-media">
            <div class="slds-media__figure">
                <img src="{!v.property.Thumbnail__c}" class="slds-avatar_large slds-avatar_circle" alt="{!v.targetFields.Title_c}"/>
            </div>
            <div class="slds-media__body">
                <lightning:layout>
                    <a onclick="{!c.navToRecord}">
                        <h3 class="slds-text-heading_small slds-m-bottom_xx-small">{!v.property.Name}</h3>
                    </a>
                </lightning:layout>
                <lightning:layout multipleRows="true">
                    <lightning:layoutItem size="6">
                        <lightning:inputField fieldName="Beds__c"/>
                    </lightning:layoutItem>
                    <lightning:layoutItem size="6">
                        <lightning:inputField fieldName="Baths__c"/>
                    </lightning:layoutItem>
                    <lightning:layoutItem size="6">
                        <lightning:inputField fieldName="Price__c"/>
                    </lightning:layoutItem>
                    <lightning:layoutItem size="6">
                        <lightning:inputField fieldName="Status__c"/>
                    </lightning:layoutItem>
                </lightning:layout>
                <lightning:layout horizontalAlign="center" class="slds-m-top_large">
                    <lightning:button variant="neutral" label="Cancel" title="Cancel" type="text" onclick="{!c.handleCancel}"/>
                    <lightning:button variant="brand" label="Submit" title="Submit" type="submit"/>
                </lightning:layout>
            </div>
        </div>
    </lightning:recordEditForm>
</aura:component>

SimilarPropertyController.js

({
    navToRecord : function (component, event, helper) {
        var navEvt = $A.get("e.force:navigateToSObject");
        navEvt.setParams({
            "recordId": component.get("v.property.Id")
        });
        navEvt.fire();
    },
    editRecord : function(component, event, helper) {
        helper.showHide(component);
    },
    handleSuccess : function(component, event, helper) {
        var toastEvent = $A.get("e.force:showToast");
        toastEvent.setParams({
            "title": "Success!",
            "message": "The property's info has been updated.",
            "type": "success"
        });
        toastEvent.fire();
        var recUpdate = $A.get("e.c:RecordUpdated");
        recUpdate.fire();
        helper.showHide(component);
    },
    handleCancel : function(component, event, helper) {
        helper.showHide(component);
        event.preventDefault();
    }
})

MyPropertyController.apxc

public with sharing class MyPropertyController {
    @AuraEnabled
    public static List<Property__c> getSimilarProperties (Id recordId, String searchCriteria, Decimal beds, Decimal price, Decimal priceRange ) {
        if (searchCriteria == 'Bedrooms') {
            return [
                SELECT Id, Name, Beds__c, Baths__c, Price__c, Broker__c, Status__c, Thumbnail__c
                FROM Property__c WHERE Id != :recordId AND Beds__c = :beds
            ];
        } else {
            Decimal range;
            if (priceRange == null) {
                range = 100000;
            } else {
                range = priceRange;
            }
            return [
                SELECT Id, Name, Beds__c, Baths__c, Price__c, Broker__c, Status__c, Thumbnail__c
                FROM Property__c WHERE Id != :recordId AND Price__c > :price - range AND Price__c < :price + range
            ];
        }
    }
}
無料で学習を続けましょう!
続けるにはアカウントにサインアップしてください。
サインアップすると次のような機能が利用できるようになります。
  • 各自のキャリア目標に合わせてパーソナライズされたおすすめが表示される
  • ハンズオン Challenge やテストでスキルを練習できる
  • 進捗状況を追跡して上司と共有できる
  • メンターやキャリアチャンスと繋がることができる