VisualforceページでのView Stateの「Internal」削減方法


【VisualforceページでのView State制限問題の解決】

VisualforceページでのView Stateが制限(135KB)を超える問題は、ユーザー体験に影響を与える重要な課題です。以下では、View Stateの構造と「Internal」コンポーネントを減らす方法を中心に解説します。


View Stateの構成要素

View Stateには以下の情報が含まれます:

  1. コントローラーとそのプロパティ

    • ページでバインドされた変数やリスト、マップなど
    • transientでない変数が対象
  2. コンポーネント構造

    • ページ上のVisualforceコンポーネントとその階層構造
  3. フォームデータ

    • ページ上のフォームの入力データ
  4. 「Internal」コンポーネント

    • Visualforceによる内部データ(例: コンポーネントの状態、構造のキャッシュ)

「Internal」コンポーネントが大きくなる原因

  1. 多量のHTML生成

    • Visualforceのデフォルトコンポーネントは、追加情報を埋め込むことでView Stateを増加させます。
  2. 繰り返しのリスト表示

    • apex:repeatやapex:dataTableが大規模なデータセットに使用されている場合。
  3. 複数のフォーム

    • フォームが複数存在する場合、各フォームの状態が保存される。
  4. ページレイアウトの複雑さ

    • DOMの階層が深いほど内部の状態保存が増える。

解決策:View Stateを最適化する方法

1. 使用していないデータの削除

  • transientの活用
    すでに利用しているようですが、動的に再生成可能なデータはすべてtransientでマークします。
public transient List<Account> accountList;

2. 大量データのクライアントサイド管理

  • サーバー側で管理するデータを最小化
    View Stateに格納されるデータ量を減らすため、JavaScriptを活用してクライアントサイドでデータを管理します。

例: データをクライアントサイドに保存する

<script>
    let accountData = [];
    function storeAccount(account) {
        accountData.push(account);
    }
</script>

3. apex:outputPanelで必要な部分のみレンダリング

  • データが条件によって表示される場合はrendered属性を使用して非表示部分を省きます。
<apex:outputPanel rendered="{!showData}">
    <!-- 必要なデータのみ -->
</apex:outputPanel>

4. actionRegionでView Stateのスコープを限定

  • フォーム全体ではなく一部だけを再送信することで、View Stateを減らします。
<apex:form>
    <apex:actionRegion>
        <apex:commandButton value="Update" action="{!updateRecords}" />
    </apex:actionRegion>
</apex:form>

5. カスタムコンポーネントを利用

  • 再利用可能なコンポーネントを設計し、ページ全体の複雑さを削減します。

例:View Stateを削減したコード設計

以下は、View Stateを抑えるための改良版コード例です:

public class AccountSearchController {
    public String searchKey { get; set; }
    public transient List<Account> results { get; private set; }

    public void search() {
        if (String.isNotBlank(searchKey)) {
            results = [SELECT Id, Name FROM Account WHERE Name LIKE :('%' + searchKey + '%')];
        } else {
            results = new List<Account>();
        }
    }
}

Visualforceページ:

<apex:page controller="AccountSearchController">
    <apex:form>
        <apex:inputText value="{!searchKey}" />
        <apex:commandButton value="Search" action="{!search}" />
    </apex:form>

    <apex:outputPanel rendered="{!NOT(ISNULL(results))}">
        <apex:dataTable value="{!results}" var="acc">
            <apex:column value="{!acc.Name}" />
        </apex:dataTable>
    </apex:outputPanel>
</apex:page>

コメント