banner
SlhwSR

SlhwSR

热爱技术的一名全栈开发者
github
bilibili

redux-immutableのプロジェクトの最適化

一、はじめに#

Immutable は、変更できないという意味で、コンピュータ上では、一度作成されると変更できないデータを指します。

Immutableオブジェクトの変更や追加、削除の操作は、新しいImmutableオブジェクトを返します。

Immutableの実装原理は、Persistent Data Structure(永続データ構造)です:

  • データを保存するためのデータ構造を使用します。
  • データが変更されると、新しいオブジェクトが返されますが、新しいオブジェクトはできるだけ以前のデータ構造を利用し、メモリの浪費を防ぎます。

つまり、古いデータを使用して新しいデータを作成する場合、古いデータが同時に使用可能であり、変更されないことを保証するために、すべてのノードをコピーすることなく、ImmutableStructural Sharing(構造共有)を使用します。

オブジェクトツリーのノードが変更された場合、このノードと影響を受ける親ノードのみを変更し、他のノードは共有されます。

以下の図のようになります:

image

二、使い方#

Immutableオブジェクトを使用するための主要なライブラリはimmutable.jsです。

immutable.js は、どのフレームワークにも基づいているかに関係なく、完全に独立したライブラリです。

これは、JavaScript に不変なデータ構造がないという問題を補うために登場し、パフォーマンスの問題を解決するために構造共有を使用しています。

内部では、完全な永続データ構造と、CollectionListMapSetRecordSeqなどの使用しやすいデータ型が提供されています。具体的には:

  • List:順序付きのインデックスセットで、JavaScript の Array に似ています。

  • Map:順序のないインデックスセットで、JavaScript の Object に似ています。

  • Set:重複のないセットです。

主なメソッドは次のとおりです:

  • fromJS ():js データを Immutable タイプのデータに変換します。
const obj = Immutable.fromJS({a:'123',b:'234'})
  • toJS ():Immutable データを JS タイプのデータに変換します。
  • is ():2 つのオブジェクトを比較します。
import { Map, is } from 'immutable'
const map1 = Map({ a: 1, b: 1, c: 1 })
const map2 = Map({ a: 1, b: 1, c: 1 })
map1 === map2   //false
Object.is(map1, map2) // false
is(map1, map2) // true
  • get (key):データまたはオブジェクトの値を取得します。

  • getIn ([]):ネストされたオブジェクトまたは配列の値を取得します。引数は配列で、位置を示します。

let abs = Immutable.fromJS({a: {b:2}});
abs.getIn(['a', 'b']) // 2
abs.getIn(['a', 'c']) // 子ノードに値がない

let arr = Immutable.fromJS([1 ,2, 3, {a: 5}]);
arr.getIn([3, 'a']); // 5
arr.getIn([3, 'c']); // 子ノードに値がない

以下の例では、次のように使用します:

import Immutable from 'immutable';
foo = Immutable.fromJS({a: {b: 1}});
bar = foo.setIn(['a', 'b'], 2);   // setInを使用して値を設定
console.log(foo.getIn(['a', 'b']));  // getInを使用して値を取得し、1を出力
console.log(foo === bar);  // falseを出力

元のjsに変更する場合は、次のようになります:

let foo = {a: {b: 1}};
let bar = foo;
bar.a.b = 2;
console.log(foo.a.b);  // 2を出力
console.log(foo === bar);  // trueを出力

三、React での使用#

Immutableを使用すると、Reactアプリケーションのパフォーマンスを向上させることができます。主にレンダリング回数の削減に表れます。

Reactのパフォーマンスを最適化する際に、重複したレンダリングを避けるために、shouldComponentUpdate()で比較を行い、trueを返すとrenderメソッドが実行されます。

Immutableは、比較を行うために深い比較の方法を使用する必要がなく、isメソッドを使用して比較を行うことができます。

また、reduxを使用する際にもImmutableを組み合わせることができ、Immutableを使用しない場合、データを変更するために深いコピーが必要です。

import '_' from 'lodash';

const Component = React.createClass({
  getInitialState() {
    return {
      data: { times: 0 }
    }
  },
  handleAdd() {
    let data = _.cloneDeep(this.state.data);
    data.times = data.times + 1;
    this.setState({ data: data });
  }
}

Immutable を使用した場合:

getInitialState() {
  return {
    data: Map({ times: 0 })
  }
},
  handleAdd() {
    this.setState({ data: this.state.data.update('times', v => v + 1) });
    // この時点ではtimesは変更されません
    console.log(this.state.data.get('times'));
  }

同様に、reduxでもデータをfromJSで処理することができます。

import * as constants from './constants'
import {fromJS} from 'immutable'
const defaultState = fromJS({ //データをimmutableデータに変換する
    home:true,
    focused:false,
    mouseIn:false,
    list:[],
    page:1,
    totalPage:1
})
export default(state=defaultState,action)=>{
    switch(action.type){
        case constants.SEARCH_FOCUS:
            return state.set('focused',true) //immutableデータを変更する
        case constants.CHANGE_HOME_ACTIVE:
            return state.set('home',action.value)
        case constants.SEARCH_BLUR:
            return state.set('focused',false)
        case constants.CHANGE_LIST:
            // return state.set('list',action.data).set('totalPage',action.totalPage)
            //mergeは効率がよく、複数のデータを一度に変更します
            return state.merge({
                list:action.data,
                totalPage:action.totalPage
            })
        case constants.MOUSE_ENTER:
            return state.set('mouseIn',true)
        case constants.MOUSE_LEAVE:
            return state.set('mouseIn',false)
        case constants.CHANGE_PAGE:
            return state.set('page',action.page)
        default:
            return state
    }
}
読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。