Redux: ミドルウェアが壊れています

作成日 2018年06月06日  ·  3コメント  ·  ソース: reduxjs/redux

バグ

重要なミドルウェアパターンが壊れています。 IMOミドルウェアソリューションの大部分は、独自の懸念をカプセル化し、他のミドルウェアの存在とは無関係です。 最近、ミドルウェアの特定のサブセット( applyMiddleware初期化パス中に他のミドルウェアと対話するときに異なる動作を示すもの)に小さな問題を引き起こすだけのパターンを壊すための変更が行われました。

ここではいくつかの例を示します。

// Make state aware of browser media queries
const mediaQueries = (mediaQueries = defaultMediaQueries): Middleware => store => {
  if (typeof window !== 'undefined') {
    const reverseMap = createReverseMap(mediaQueries)

    const handleMediaChange = ({media, matches}: MediaChangedActionPayload) =>
      store.dispatch(mediaChanged(reverseMap[media], matches))

    const addMatchListener = (media: string) => {
      const match = window.matchMedia(media)
      match.addListener(handleMediaChange)
      return match.matches
    }

    values(mediaQueries).forEach(media => 
      handleMediaChange({media, matches: addMatchListener(media)}))
  }

  return next => (action: any) => next(action)
}

もう一つの例:

// Make state aware of user adblockers
const adBlockDetection: Middleware = store => {
  if (typeof document !== 'undefined' && !document.getElementById('XMpADSwgbPUC')) {
    store.dispatch({type: AD_BLOCKER_DETECTED, payload: true})
  }
  return next => (action: any) => next(action)
}

もう一つの例:

// Make state aware of socket connectivity and allow synchronisation of actions
const socketMiddleware = ({actionCreator, url, dataSync}) => store => {
  const socket = new WebSocket(url.replace(/(http|https)/, 'ws'))

  socket.addEventListener('message', ({data}) => {
    store.dispatch(JSON.parse(data))
  })

  socket.addEventListener('open', () => {
    socket.send(syncCreator(CONNECT_TO_DOMAIN, store.getState(), null, socket))
    store.dispatch(actionCreator({connected: true}))
  })

  socket.addEventListener('close', reason => {
    store.dispatch(actionCreator({connected: false}))
  })

  return next => action => {
    if (dataSync.hasOwnProperty(action.type)) {
      socket.send(syncCreator(action.type, store.getState(), action.payload, socket))
    }
    return next(action)
  }
}

現在の行動は何ですか?

applyMiddleware中に次のエラーがスローされ、基本的にアプリケーションが破損します。

Uncaught Error: Dispatching while constructing your middleware is not allowed. Other middleware would not be applied to this dispatch

上記のミドルウェアをnext =>関数(以下のように)で閉じるようにリファクタリングしても違いはありません(ただし、明らかに実行可能なソリューションでもありません)。

// Still broken:
const mediaQueries = (mediaQueries = defaultMediaQueries): Middleware => store => next => {
  // ...middlewareCodeGoesHere...
  return (action: any) => next(action)
}

期待される動作は何ですか?

アプリを壊さないでください。 必要に応じて警告をログに記録してください。無視できます。私のユースケースの100%で、_他のミドルウェアがそのディスパッチを処理できるかどうかは気にしない_からです。 ミドルウェアコンテキスト内からのディスパッチがスタック内の他のミドルウェアと相互作用する必要がある正当な理由はほとんどない(またはあるべきである)と強く疑っています。少なくともミドルウェアへの暗黙の順序依存性)。

どのバージョンのRedux、どのブラウザとOSがこの問題の影響を受けますか?

このPRまで働いた。

最も参考になるコメント

@markeriksonええ私はその問題を見てきました。 新しい設計が「解決する」重要な問題は次のとおりです。

問題は次のとおりです。ミドルウェアを適用しているときにリスナーが起動するため、 store.dispatchを呼び出すと、ミドルウェアがないディスパッチが呼び出され、分析ミドルウェアはイベント

これはIMOであり、アプリケーション開発者が処理する必要のある実装の詳細であり、_ほとんどのミドルウェアの動作を壊す_ものではありません。 アプリケーション開発者は、エラーをスローする代わりに警告を表示することで、問題を特定し、独自のミドルウェアをリファクタリングして問題に対処できます。

現在の状態では、この内部ディスパッチパターン(基本的にはリスナーをインスタンス化する必要があるもの)を使用する、サードパーティのミドルウェアを含む既存のミドルウェアはすべて壊れています。

残念ながら、Typescriptを使用しているため、3.xを使用することはできません。正しい入力は、4.xのみであり、一般に、コア部分のレガシーバージョンに固執することはありません。タイピングが問題ではなかったとしても、アプリケーションロジック。

そして私の意見では、エラーメッセージ自体でさえ、それが実際にどれほど重要でないかを示唆しています。「問題」は、 Other middleware would not be applied to this dispatchが実際に望まれることはめったになく、これまでのところ、特定の1つの問題にすぎないことです。分析ミドルウェアがルーターからディスパッチされたアクションに依存していたユースケース。

重要なのは、reduxの「修正」は、修正しようとしていたコードを壊してしまうことです。 ルーターのミドルウェアを壊します。 そのミドルウェア(および他のすべての同様のミドルウェア)の作成者は、ライブラリの4.x互換バージョンをリリースする必要があります。これにより、コンシューマーが実装する必要のある、手動でディスパッチされた「ストアレディ」アクションの実装の詳細を公開する必要があります。

ミドルウェアライブラリの使用は、単にパッケージをインポートしてミドルウェア配列に挿入することから、ストアの作成が完了した後しばらくして、アプリの作成者が任意の「ストアレディ」アクションをディスパッチするためのハックな方法を見つけることをさらに要求するように変更されました。使用される前に。 そして今、すべてのミドルウェアが同じアクションタイプに準拠している必要があります。そうでない場合、アプリの作成者は、ミドルウェアの作成者が実装したAPIに一致するさまざまなタイプで、複数の「ストアレディ」アクションをディスパッチする必要があります。

これは本当の混乱であり、この場合の「病気」よりも「治癒」は明らかにはるかに悪いです。

全てのコメント3件

ミドルウェアの初期化プロセスは、リンクしたPRの4.0で明示的に変更されました。 これは意図的な設計上の決定であり、#1240を解決することを目的としています。

ミドルウェアのロジックを変更して、手動でディスパッチされた「ストアの準備ができました」アクションを待つ以外に、ユースケースについてすぐに提案できるかどうかはわかりません。 代わりに3.xを使用することを検討することもできます。

@markeriksonええ私はその問題を見てきました。 新しい設計が「解決する」重要な問題は次のとおりです。

問題は次のとおりです。ミドルウェアを適用しているときにリスナーが起動するため、 store.dispatchを呼び出すと、ミドルウェアがないディスパッチが呼び出され、分析ミドルウェアはイベント

これはIMOであり、アプリケーション開発者が処理する必要のある実装の詳細であり、_ほとんどのミドルウェアの動作を壊す_ものではありません。 アプリケーション開発者は、エラーをスローする代わりに警告を表示することで、問題を特定し、独自のミドルウェアをリファクタリングして問題に対処できます。

現在の状態では、この内部ディスパッチパターン(基本的にはリスナーをインスタンス化する必要があるもの)を使用する、サードパーティのミドルウェアを含む既存のミドルウェアはすべて壊れています。

残念ながら、Typescriptを使用しているため、3.xを使用することはできません。正しい入力は、4.xのみであり、一般に、コア部分のレガシーバージョンに固執することはありません。タイピングが問題ではなかったとしても、アプリケーションロジック。

そして私の意見では、エラーメッセージ自体でさえ、それが実際にどれほど重要でないかを示唆しています。「問題」は、 Other middleware would not be applied to this dispatchが実際に望まれることはめったになく、これまでのところ、特定の1つの問題にすぎないことです。分析ミドルウェアがルーターからディスパッチされたアクションに依存していたユースケース。

重要なのは、reduxの「修正」は、修正しようとしていたコードを壊してしまうことです。 ルーターのミドルウェアを壊します。 そのミドルウェア(および他のすべての同様のミドルウェア)の作成者は、ライブラリの4.x互換バージョンをリリースする必要があります。これにより、コンシューマーが実装する必要のある、手動でディスパッチされた「ストアレディ」アクションの実装の詳細を公開する必要があります。

ミドルウェアライブラリの使用は、単にパッケージをインポートしてミドルウェア配列に挿入することから、ストアの作成が完了した後しばらくして、アプリの作成者が任意の「ストアレディ」アクションをディスパッチするためのハックな方法を見つけることをさらに要求するように変更されました。使用される前に。 そして今、すべてのミドルウェアが同じアクションタイプに準拠している必要があります。そうでない場合、アプリの作成者は、ミドルウェアの作成者が実装したAPIに一致するさまざまなタイプで、複数の「ストアレディ」アクションをディスパッチする必要があります。

これは本当の混乱であり、この場合の「病気」よりも「治癒」は明らかにはるかに悪いです。

すべての例を機能させることは可能です。 applyMiddlewareの後にディスパッチするだけです。 おそらく、ある種のsetupMiddleware(store)関数またはストアエンハンサーにあります。

エラーは、ユーザーが非常に明白でない原因を持つエッジケースをヒットできるようにするために意図的に導入されました( applyMiddlewareの内部に精通している場合を除く)。 Reduxは可能な限りユーザーエラーを防ぐというスタンスを取っているので、これがなくなることはありません。

1つの代替手段は、ミドルウェアが一種のafterApplyイベントとして登録できるある種のコールバックである可能性があります。 そうすれば、すべてが適用された後、正しい時間に発送されることが保証されます。 それを熟考するのは興味深いでしょう。

このページは役に立ちましたか?
0 / 5 - 0 評価