ReduxでImmutable.JSを使う#

目次#

  • なぜImmutable.JSのようなイミュータブルに特化したライブラリを使うべきか
  • Immutable.JSは、なぜ、Immutableライブラリに選ぶべきか
  • Immutableを使う際の問題点は何か
  • Immutable.JSを使う際の問題点は何か?
  • Immutable.JSは努力する価値がありますか?
  • ReduxでImmutable.JSを使うための意見的ベストプラクティスは?

Why should I use an immutable-focused library such as Immutable.JS?#

Immutable.JS 等のImmutable Focused Libliariesは、イミューテッドのような、イミューテッドを重視するライブラリです。JS は、JavaScript に内在する不変性の問題を克服するために設計されており、不変性のすべての利点を、アプリケーションが必要とするパフォーマンスとともに提供します。

このようなライブラリを使用するか、あるいはプレーンな JavaScript に固執するかは、アプリに別の依存関係を追加することにどれだけ抵抗があるか、あるいは、JavaScript の不変性へのアプローチに固有の落とし穴を回避できるとどれだけ確信しているかによって決まります。 特に、アプリケーションのパフォーマンスを低下させたり、完全に壊してしまうような偶発的な変異を防ぐために、値の更新やコピー時に JavaScript が何を行うかを深く理解していることを確認します。Immutable.js と関数型プログラミングの概念

  • Pros and Cons of using immutability with React.js
  • Why should I choose Immutable.JS as an immutable library?#

    Immutable.JS は JavaScript における immutability の制限を克服しようと、パフォーマンスの高い方法で Immutability を提供するために設計されました。 その主な利点は次のとおりです:

    保証された不変性#

    Immutable.JS オブジェクトにカプセル化されたデータは、決して変更されることはありません。 常に新しいコピーが返されます。 これはJavaScriptとは対照的で、ある操作ではデータが変化せず(例:map, filter, concat, forEachなどのArrayメソッド)、ある操作では変化します(例:Arrayのpop, push, spliceなど)。また、データのソートやフィルタリング、グループ化、反転、フラット化、サブセットの作成など、データを操作するための豊富なメソッド群を提供する。 これは、Immutable データ構造を使用すると、多くの高価なコピーを伴う可能性があるため、そのパワーの鍵になります。 特に、ネストされた Redux 状態ツリーのような大規模で複雑なデータ セットを不変に操作すると、オブジェクトの中間コピーが多数生成され、ブラウザのガベージコレクターが整理するためにメモリを消費してパフォーマンスを低下させることがあります。 また、すぐに捨てられてしまう不必要な(そしてコストのかかる)クローン化された中間データを作成することなく、複雑な連鎖処理を実行することができます。

    もちろん、これを見ることはありません。 むしろ、Immutable.JSの内部で、連鎖的に呼び出されるメソッドから生成される中間データが、自由に変異させられるのです。

    Further Information#

    Articles

    • Immutable.js, persistent data structures and structural sharing
    • PDF.XXX.XXX.XXX.XXX.XXX.XXX.XXX.XXX.XXX.XXX.XXX.XXX.XXX.XXX.XXX.XXX.XXX.XXX.XXX.XXX.XXX.XXX.XXX.XXX.XXX: JavaScript Immutability – Don’t go changing

    ライブラリ

    • Immutable.js

    Immutable.JS を使う際の問題点は?#

    強力ではあるものの、それなりの問題があるので Immutable.JS は慎重に用いる必要がある。

    Difficult to interoperate with#

    JavaScript は immutable データ構造を提供しません。 そのため、Immutable.JS が immutable を保証するためには、データを Immutable.JS オブジェクト (MapList など) にカプセル化する必要があるのです。

    たとえば、標準的な JavaScript のドットまたはブラケット記法でオブジェクトのプロパティを参照することはできなくなります。 その代わり、Immutable.JS の get() または getIn() メソッドを介して参照する必要があります。このメソッドでは、それぞれがプロパティ キーを表す文字列の配列を介してプロパティにアクセスする、厄介な構文を使用します。

    このため、自分のコードだけでなく、lodash や ramda のような、プレーンな JavaScript オブジェクトを期待する他のライブラリとの相互運用が困難になります。しかしこのメソッドは非常に遅く、これを多用すると Immutable.JS が提供するパフォーマンスの利点が損なわれてしまいます。

    一度使用すると、Immutable.JS はあなたのコードベース全体に広がります。

    このことは、Immutable.JS をコードベース全体に広げる効果があり、そのような外部依存がないほうがよいコンポーネントも潜在的に含まれます。 コードベース全体が、何が Immutable.JS オブジェクトで、何がそうでないかを知る必要があります。

    この問題は、以下のベストプラクティスのセクションで説明するように、アプリケーションロジックをデータ構造から切り離すことで回避することが可能です。

    Not suitable for small values that change often#

    Immutable.JS works best for collections of data, and the larger the better.If Immutable.JS own get() and getIn() methods, you can no longer use JavaScript’s destructuring operator (or the proposed Object spread operator), making your code more verbose.

    Exceptable small values for frequently change #

    Immutable.JS works best for collection of data, the larger is better.

    ただし、これはReduxのステートツリーには当てはまらないので、(通常は)大きなデータの集まりとして表現されることに注意してください。 このようなオブジェクトを検査すると、気にしない Immutable.JS 固有のプロパティのネストされた階層全体が明らかになり、気にする実際のデータは数層深くカプセル化されるため、デバッグが困難になることがあります。

    オブジェクト参照を破壊し、パフォーマンスの低下を招く#

    不変性の主な利点の 1 つは、浅い等式チェックを可能にし、パフォーマンスを劇的に向上させることです。

    しかし、Immutable.JS オブジェクト内にカプセル化されたデータがそれ自体オブジェクトである場合、浅いチェックは機能しない。 これは、Immutable.JSのtoJS()メソッドが、Immutable.JSオブジェクトに含まれるデータをJavaScriptの値として返すため、呼ばれるたびに新しいオブジェクトが作成され、カプセル化されたデータとの参照が壊れるからです。

    したがって、たとえば toJS() を 2 回呼び出し、結果を 2 つの異なる変数に代入すると、オブジェクトの値自体は変更されていないにもかかわらず、これら 2 つの変数の等値検査に失敗することになります。 たとえば、以下の mapStateToProps から返される todos プロパによって参照される値は常に異なるオブジェクトであるため、浅い等価検査に失敗します。

    // AVOID .toJS() in mapStateToProps
    function mapStateToProps(state) {
    return {
    todos: state.get(‘todos’).toJS() // 常に新しいオブジェクト
    } } { mapStateToProps.toTos(‘tojS’) {
    return { { mapStateToProps.toTos: state.get(‘todos’).tojS() // 常に新しいオブジェクト
    }

    コピー

    シャローチェックが失敗すると、React-Reduxはコンポーネントの再レンダリングを引き起こします。 このように mapStateToPropstoJS() を使用すると、値が変更されない場合でも常にコンポーネントの再レンダリングが発生し、パフォーマンスに大きな影響を与えます。

    これは、以下のベスト プラクティスのセクションで説明するように、高次コンポーネントで toJS() を使用することで防ぐことができます。js、永続的なデータ構造と構造共有

  • 不変のデータ構造と JavaScript
  • React.js pure render performance anti-pattern
  • Building Efficient UI with React and Redux
  • Chrome Extension

    • Immutable Object Formatter

    Is Using Immutable.JS worth the effort?#

    Frequently, yes. 考慮すべきさまざまなトレードオフや意見がありますが、Immutable.JS を使用する正当な理由がたくさんあります。 コンポーネントは、レンダリングすべきでないときに再レンダリングし、レンダリングすべきときにレンダリングを拒否し、レンダリングの問題を引き起こしているバグを追跡することは困難です。 Immutable.JS を使用すると、この問題は単に存在しないため、アプリからバグのクラス全体を取り除くことができます。

    これに加えて、パフォーマンスとデータ操作用の豊富な API が、Immutable.JS が努力する価値がある理由となっています。 アクションをディスパッチしても何も起こらない

    Redux で Immutable.JS を使用するための意見あるベスト プラクティスは何ですか。#

    Immutable.JS はアプリに大きな信頼性とパフォーマンスの向上をもたらすことができますが、正しく使用することが必要です。 Immutable.JSを使用する場合(必須ではありませんし、他にも使用できるImmutableライブラリがあることをお忘れなく)、以下の意見に基づくベストプラクティスに従うことで、潜在的に引き起こしうる問題でつまずくことなく、その機能を最大限に活用できるようになります。

    Further Information#

    記事

    • Immutable Data Structures and JavaScript

    ReduxのステートツリーをすべてImmutable.JSにすること。

    • Immutable.JS の fromJS() 関数を使用してツリーを作成します。Redux 自身がステートツリーがプレーンな JavaScript オブジェクトであることを期待しているので、redux-immutable のような combineReducers 関数の Immutable.JS 対応バージョンを使用します。

    • Immutable.JS Map または List に Immutable.JS を使用して JavaScript オブジェクトを追加する場合、

    • と入力します。

    //
    const newObj = { key: value } を回避する。
    const newState = state.setIn(, newObj)
    // newObj は Immutable.JS Map ではなく JavaScript オブジェクトとして追加されました

    // 推奨

    const newObj = { key: value } … 続きを読む
    const newState = state.setIn(, fromJS(newObj))
    // newObj は Immutable.JS Map になりました

    コピー

    Further Information#

    記事

    • Immutable Data Structures and JavaScript

    ライブラリ

    • redux-immutable

    Use Immutable.JS

    しかし、ダム コンポーネントでは Immutable.JS を使用しないでください。

    Further Information#

    Articles

    • Immutable Data Structures and JavaScript
    • Smart and Dumb Components in React

    Limit your use of toJS()#

    toJS() is a expensive function and negifies the purpose of using Immutable.JS.JS.

    Further Information#

    Discussions

    • Lee Byron on Twitter: “Perf tip for #immutablejs…”

    セレクタは Immutable.JS オブジェクトを返すべき#

    Always.

    • セレクタで .toJS() を呼び出すことによる不要な再レンダリングを避けることができます (.toJS() は常に新しいオブジェクトを返すので)。
      • .toJS() を呼び出すセレクタでメモすることは可能ですが、メモせずに Immutable.js オブジェクトを返すだけで十分な場合は、それは冗長なことです。
    • これは、セレクタのための一貫したインターフェイスを確立します。Immutable.js オブジェクトとプレーン JavaScript オブジェクトのどちらが返されるかを追跡する必要はありません。

    Use Immutable.JS objects in your Smart Components#

    React Redux の connect 機能を介してストアにアクセスするスマートコンポーネントには、セレクターが返す Immutable.Js 値を使用しなければなりません。 不必要なコンポーネントの再レンダリングによる潜在的な問題を回避することを確認してください。 必要であれば、reselect などのライブラリを使ってセレクタをメモしてください。 派生データの計算

  • FAQ: Immutable Data
  • Reselect ドキュメンテーション。 Immutable.js で Reselect を使用するにはどうすればよいですか?
  • 記事

    • Redux パターンとアンチパターン

    ライブラリ

    • Reselect: Redux用セレクタライブラリ

    Never use toJS() in mapStateToProps#

    toJS()を使ってImmutable.JSオブジェクトをJavaScriptオブジェクトに変換すると、毎回新しいオブジェクトが返されます。 mapStateToProps でこれを行うと、ステート ツリーが変更されるたびにコンポーネントがオブジェクトが変更されたと考えるようになり、不要な再描画が発生します。

    Further Information#

    ドキュメント

    • FAQ: Immutable Data

    Dumb Components で Immutable.JS を使用しない#

    Dumb Components は純粋であるべきで、同じ入力で同じ出力を生成し、外部依存がないものである。 そのようなコンポーネントに Immutable.JS オブジェクトを prop として渡すと、prop の値を抽出したり、その他の操作をするために Immutable.JS に依存することになります。

    このような依存関係は、コンポーネントを不純物に変え、コンポーネントをより困難にし、コンポーネントの再利用やリファクタリングを不必要に困難にしています。

    Further Information#

    Articles

    • Immutable Data Structures and JavaScript
    • Smart and Dumb Components in React
    • Tips For a Better Redux Architecture: Lessons for Enterprise Scale

    Use a Higher Order Component to convert your Smart Component’s Immutable.JS props to your Dumb Component’s JavaScript props#

    Something needs to map the Immutable.JS props in your Smart Component to the pure JavaScript props used in your Dumb Component.Dumb Component, “Immutable “は、Smart Component のプロップを、Dumb Component のプロップにマッピングするために必要です。 その何かとは、Smart Component から Immutable.JS プロップを単に受け取り、toJS() を使用してそれらをプレーン JavaScript プロップに変換し、それを Dumb Component に渡す Higher Order Component (HOC) のことです。 同様の HOC は、便宜上 NPM パッケージとして利用可能です: with-immutable-props-to-js です。

    import React from ‘react’
    import { Iterable } from ‘immutable’
    export const toJS = (訳注: 原文のまま) WrappedComponent => wrappedComponentProps => {
    const KEY = 0
    const VALUE = 1
    const propsJS = Object.PropsJS、
    const VALUE = 1entries(wrappedComponentProps).reduce(
    (newProps, wrappedComponentProp) => {
    newProps] = Iterable.Entry(WrapComponentProps).Reduce((newProps,WrapComponentProps)=

    )。isIterable(

    wrappedComponentProp
    )
    ? wrappedComponentProp.toJS()
    : wrappedComponentProp
    return newProps
    },
    {}.
    )
    return <WrappedComponent {…propsJS}。 />
    }

    コピー

    そして、これをスマートコンポーネントで使用する方法は以下の通りです:

    import { connect } from ‘react-redux’
    import { toJS } from ‘./to-js’
    import DumbComponent from ‘./dumb.Inc.component’
    const mapStateToProps = state => {
    return {
    // obj は Smart Component では Immutable オブジェクトですが、toJS によってプレーンな
    // JavaScript オブジェクトに変換され、純粋な JavaScript
    // オブジェクトとして DumbComponent に渡されています。 mapStateToProps では Immutable.JS オブジェクトであるため、
    // 誤って再描画されることはないでしょう。
    obj: getImmutableObjectFromStateTree(state)
    }.
    }
    export default connect(mapStateToProps)(toJS(DumbComponent))

    コピー

    HOC 内で Immutable.JS オブジェクトをプレーン JavaScript 値に変換することにより、ダム コンポーネントの移植性を実現しますが、スマート コンポーネントで toJS() を使用した場合のパフォーマンスのヒットは発生しません。 しかし、ほとんどのアプリではそうではなく、ダム コンポーネントから Immutable.JS を除外することの利点 (保守性、移植性、テストの容易さ) は、それを含めることによるパフォーマンスの向上をはるかに上回ります。 パフォーマンスの問題と同様に、何を最適化するかを決定する前に、まずパフォーマンスのチェックを実施してください。

    Further Information#

    Documentation

    • React: Higher-Order Components

    Articles

    • React Higher Order Components in depth

    Discussion

    • Reddit: acemarke and cpsubrian comments on Dan Abramov.Blog(英語):Dan Abramov が React の高次コンポーネントについてコメントしました。 Reduxはアーキテクチャでもデザインパターンでもなく、ただのライブラリです。

    Gists

    • cpsubrian: Redux/react-router/immutable ‘smart’ components のための React デコレーター

    Use the Immutable Object Formatter Chrome Extension to Aid Debugging#

    Install the Immutable Object Formatter , and inspect your Immutable.JS data without seeing the noise of Immutable.JS own object properties.

    (英語)。

    コメントを残す

    メールアドレスが公開されることはありません。