Immutable.jsでファイルデータの不変性を実現

不変なファイル処理の必要性

JavaScriptでのBlobやFileの操作は、しばしば意図しないデータの変更を引き起こします。例えば:


// 伝統的なファイルデータ処理のリスク
const fileData = { blob: new Blob(['test']), name: 'data.txt' };
const processedData = fileData;
processedData.name = 'modified.txt';
console.log(fileData.name); // 意外にも'modified.txt'に変更される

Immutable.jsの不変データ構造を使用することで、データの不変性を保証し、操作の安全性を向上させることができます。

Immutable.jsの基本機能

Immutable.jsの主なデータ構造は以下の通りです:

  • OrderedSet(順序付きセット)
  • Map(キー-値ペアの集合)
  • Record(固定プロパティを持つオブジェクト)

これらの構造は、データの更新時に寛大なコピーを実施することでパフォーマンスを最適化します。

Blobデータの不変性管理

Blobデータを安全に管理する方法:


import { Map } from 'immutable';

// 不変なBlobオブジェクト作成
const immutableBlob = Map({
  data: new Blob(['Hello, Immutable!'], { type: 'text/plain' }),
  size: 16,
  type: 'text/plain'
});

// 安全なプロパティアクセス
console.log(immutableBlob.get('type')); // 'text/plain'

// 更新操作は新オブジェクトを返す
const newBlob = immutableBlob.set('name', 'immutable-file.txt');
console.log(immutableBlob.has('name')); // false(元のオブジェクトは変更されない)

Fileオブジェクトの不変性管理

Fileの操作を安全に行う方法:


import { fromJS } from 'immutable';

// Fileアップロードハンドラ
function handleFileUpload(file) {
  return fromJS({
    fileData: file,
    metadata: {
      name: file.name,
      size: file.size,
      type: file.type,
      lastModified: file.lastModified
    },
    status: 'pending'
  });
}

// 使用例
const fileInput = document.querySelector('input[type="file"]');
fileInput.addEventListener('change', (e) => {
  const file = e.target.files[0];
  const immutableFile = handleFileUpload(file);
  
  // 不変性を保持したまま処理を続行
  const processedFile = immutableFile.set('status', 'processed');
});

ファイル操作のユーティリティ関数

以下のユーティリティ関数を使用してファイル操作を簡素化します:


import { Map, List } from 'immutable';

const FileUtils = {
  createImmutableFile(file) {
    return Map({
      raw: file,
      info: Map({
        name: file.name,
        type: file.type,
        size: file.size,
        lastModified: file.lastModified
      }),
      content: null
    });
  },
  
  async readFileContent(immutableFile) {
    return new Promise((resolve) => {
      const reader = new FileReader();
      reader.onload = (e) => {
        // 嵌套されたプロパティを更新
        const updatedFile = immutableFile.setIn(['content'], e.target.result);
        resolve(updatedFile);
      };
      reader.readAsText(immutableFile.get('raw'));
    });
  },
  
  mergeFiles(files) {
    return List(files.map(this.createImmutableFile));
  }
};

export default FileUtils;

応用例

1. ファイルアップロード管理


import { List } from 'immutable';
import FileUtils from './utils/fileUtils';

class FileUploadManager {
  constructor() {
    this.uploadQueue = List();
  }
  
  addFile(file) {
    const immutableFile = FileUtils.createImmutableFile(file);
    this.uploadQueue = this.uploadQueue.concat([immutableFile]);
  }
  
  removeFile(index) {
    this.uploadQueue = this.uploadQueue.delete(index);
  }
  
  async processAllFiles() {
    return Promise.all(
      this.uploadQueue.map(file => 
        FileUtils.readFileContent(file)
      ).toArray()
    );
  }
}

2. ファイルの検索とフィルター


function filterFilesByType(fileList, mimeType) {
  return fileList.filter(file => 
    file.getIn(['info', 'type']).startsWith(mimeType)
  );
}

function searchFiles(fileList, query) {
  const lowerQuery = query.toLowerCase();
  return fileList.filter(file => 
    file.getIn(['info', 'name']).toLowerCase().includes(lowerQuery)
  );
}

性能最適化とベストプラクティス

  • データがアプリケーションに入ってきた段階で不変オブジェクトに変換してください
  • 大規模なデータ操作時はwithMutationsメソッドを使用してください
  • 大容量ファイルの場合は参照のみを格納するようにしてください
  • 操作履歴を維持してリダオ操作を可能にします

結論

Immutable.jsを使用することで、以下のメリットを享受できます:

  • データの不変性保証
  • 予測可能な状態管理
  • 効率的なネストデータ操作
  • 安全な並列操作

Immutable.jsはBlobやFileを直接サポートしていませんが、今回紹介した方法で安全で効率的なファイル処理を実現できます。

詳細なAPI情報は公式ドキュメントやソースコードを参照してください。

タグ: Immutable.js File操作 blob 不変性管理

7月10日 17:39 投稿