web-dev-qa-db-ja.com

状態はreact-reduxアプリのセレクターにどのように渡されますか?

MapStateToProps関数がメモ化を使用している例に出くわしました。 「state」パラメーターがメモ化されたセレクターにどのように渡されるのか疑問に思っていました。再選択とreduxのドキュメントを確認したところ、mapStateToPropsは状態を引数として受け入れる関数を返すことができ、接続デコレータが状態を渡す関数である可能性がありますが、よくわかりません。誰かが光を当ててくれませんか?

views/tracklist/index.js

const mapStateToProps = createSelector(
  getBrowserMedia,
  getPlayerIsPlaying,
  getPlayerTrackId,
  getCurrentTracklist,
  getTracksForCurrentTracklist,
  (media, isPlaying, playerTrackId, tracklist, tracks) => ({
    displayLoadingIndicator: tracklist.isPending || tracklist.hasNextPage,
    isMediaLarge: !!media.large,
    isPlaying,
    pause: audio.pause,
    pauseInfiniteScroll: tracklist.isPending || !tracklist.hasNextPage,
    play: audio.play,
    selectedTrackId: playerTrackId,
    tracklistId: tracklist.id,
    tracks
  })
);

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(Tracklist);

core/tracklists /selectors.js

export function getCurrentTracklist(state) {
//  console.log(state);
  let tracklists = getTracklists(state);
  return tracklists.get(tracklists.get('currentTracklistId'));
}

export const getTracksForCurrentTracklist = createSelector(
  getCurrentPage,
  getCurrentTrackIds,
  getTracks,
  (currentPage, trackIds, tracks) => {
    return trackIds
      .slice(0, currentPage * TRACKS_PER_PAGE)
      .map(id => tracks.get(id));
  }
);
9
krikey

react-reduxからConnectコンポーネントを使用するときに状態がセレクターに渡される方法の概要

セレクターとは何ですか?

セレクターは、ソースからデータのサブセットを抽出します。

Reduxストアを「フロントエンドデータベース」と考えてみましょう。目的のためにデータベースで合計データのサブセットを抽出する場合は、クエリを実行します。同様に、セレクターはReduxストアへのクエリです。

最も単純なケースでは、セレクターはストア全体の状態を返すことができます。

再選択のドキュメントは、セレクターを使用する3つの大きな理由を示しています

  • セレクターは派生データを計算できるため、Reduxは最小限の状態を保存できます。
  • セレクターは効率的です。セレクターは、引数の1つが変更されない限り、再計算されません。
  • セレクターは構成可能です。それらは他のセレクターへの入力として使用できます。

高次コンポーネントとは何ですか?

高階コンポーネントは、既存のコンポーネントを受け取り、新しいコンポーネントを返す関数です。

Connectは、セレクターが与えられる高階コンポーネントです

this brilliant Gistから引用しました。これは、接続の良い説明を提供します。

connect()は、Redux関連の小道具をコンポーネントに挿入する関数です。

Connectは、ReactコンポーネントにReduxストアを認識させる高階コンポーネントです。connectを呼び出すと、mapStateToPropsとmapDispatchToPropsを渡すことができます。これらの関数は方法を定義します。 =新しいコンポーネントはreduxストアに接続されます。

MapStateToProps関数を引数として渡すことで、状態へのアクセスを許可できます。

MapDispatchToPropsを介してアクションクリエーターをstore.dispatchにバインドすることもできます。これの利点は、コンポーネントがstore.dispatchにアクセスできるようにするためにストア全体を渡す必要がないため、コンポーネントが独自のReduxアクションをディスパッチできることです。

Connectに渡すmapStateToProps関数はセレクターです

React-reduxドキュメントから

MapStateToProps関数は、Reduxストア全体の状態の単一の引数を取り、小道具として渡されるオブジェクトを返します。セレクターと呼ばれることもあります。

Reduxストアへのクエリの結果としてmapStateToPropsによって返されるオブジェクトについて考えてみてください。結果として

MapStateToProps関数は通常、プレーンオブジェクトを返す必要があります。

mapStateToPropsを呼び出した結果は、通常、reduxストアから抽出したデータを表すプレーンオブジェクトになります。

高次のConnectコンポーネントを使用すると、この新しいオブジェクトのデータをコンポーネントの既存の小道具とマージすることで、既存のコンポーネントの機能を拡張できます。

セレクターは単なる関数なので、接続コンポーネントを使用してReduxストアに接続することもできます。

ただし、場合によっては関数を返すことができます。なぜこれを行うのでしょうか?

mapStateToPropsで関数を再取得することにより、コンポーネントのレンダリングサイクルをハイジャックし、パフォーマンスを最適化できます

レンダリングパフォーマンスをさらに制御する必要がある高度なシナリオでは、mapStateToProps()も関数を返すことができます。この場合、その関数は特定のコンポーネントインスタンスのmapStateToProps()として使用されます。これにより、インスタンスごとのメモ化を行うことができます。

MapStateToProps関数を引数として高次コンポーネントに渡すことにより、Reduxストアで状態が変更されるたびに、接続されたコンポーネントが更新されます。

これらの更新が非常に頻繁に発生する場合、または状態ツリーが大きい場合は、再選択ライブラリを使用すると、memoizedセレクターを使用できるので便利です。

この派手なWordは、セレクター呼び出しの結果が再度取得する必要がある場合に備えて保存されることを意味します。

したがって、mapStatesToPropsが関数ではなくプレーンオブジェクトを返した場合、ストアの状態が変更されるたびに、コンポーネントの新しい小道具が作成されます。

セレクターをストアに接続する

React Reduxを使用している場合は、mapStateToProps()内の通常の関数としてセレクターを呼び出すことができます。

import { getVisibleTodos } from '../selectors'

const mapStateToProps = (state) => {
  return {
    todos: getVisibleTodos(state)
  }
}

複数のコンポーネント間でセレクターを共有する

再選択ライブラリを使用する場合、コンポーネントと同じように再選択セレクターの小道具を与えることができます。これにより、複数のコンポーネント間でセレクターを共有できます。

それぞれが独自のIDを持つ複数のtoDoリストがあるとします。各toDoリストインスタンスに同じgetVisibleTodosセレクターを使用しますが、小道具として異なるIDを渡すだけです。

ただし、これに関する問題は、createSelectorがキャッシュされた値を返すのは、引数のセットが前の引数のセットと同じである場合のみであるということです。

再選択のドキュメントは、mapStateToProps内で関数を返すことでこの制限を克服できることを指摘しています。

複数のコンポーネント間でセレクターを共有し、メモ化を保持するには、コンポーネントの各インスタンスにセレクターの独自のプライベートコピーが必要です。接続に指定されたmapStateToProps引数がオブジェクトではなく関数を返す場合、それを使用して、コンテナーのインスタンスごとに個別のmapStateToProps関数を作成します。

MapStateToProps内で関数を返すことにより、この制限を克服でき、メモ化は正しく機能します。

より詳細な説明については、 this を参照してください。

25
therewillbecode

とても簡単です:例を挙げましょう、私はmapStateToPropsこのようにしています:

_function mapStateToProps(state) {
  return {
    categoryHistory: getCategoryHistory(state,'extended')
  }
}
_

次に、次のようにselectorを作成しました。

_export const getCategoryHistory = (state, type) => createSelector([getTaxonomy, selectedCategoryID], (categories, categoryID) => categories.getIn([type, categoryID]) || [])(state)
_

解決策は、createSelector()を呼び出してstateをパラメーターとして渡すことです。

createSelector()(state)

セレクター内では、通過させたいすべてのパラメーターを使用できます。

2

あなたが言及した場合、mapStateToPropsは状態を取り込んでオブジェクトを返す関数です。 mapStateToPropsを接続に渡したとき、connectによって提供された状態を引数として受け入れる関数を渡しました。

createSelectorは、状態を取り込んでオブジェクトを返すこともできる関数を作成します。したがって、それをmapStateToPropsに割り当てて、connectに渡すことができます。

ドキュメントには、通常、次のものがあります。

const mapStateToProps = (state) => {
    whatever code
}

そして

export default connect(mapStateToProps, mapDispatchToProps)(Component)

ここで、mapStateToPropsは、connectによって提供される状態引数を取ります。

ただし、次のようにmapStateToPropsをセレクターにすることができます。

const mapStateToProps = createSelector(
    whatever code
)

これは、createSelectorが次のような状態になる可能性があるためです。

createSelector(whatever code)(state)

mapStateToPropsがドキュメントで行うのと同じように、オブジェクトを返します。

0
ubikayu