2017-11-21 6 views
1

皆様、ありがとうございます。ES6 Promises - 遅延を使用せずに、React componentDidMount関数でインスタンス化されたオブジェクトへの最終的なアクセスを保証するにはどうすればよいですか?

私は初めてES6ネイティブの約束事を使用しています(以前は、QまたはAngularの$ qサービスを使用していました)。私は、延期を利用することで簡単に解決できる問題があり、ES6の約束がそれらを使用しないことを発見するのに驚いた。

私はさらに、ブログで多くの人々がアンチパターンとしての使用を参照していることに驚きました。なぜなら、彼らの例は私が決して遅れをとって使用していなかった場所だったので、何かが足りなくなっているかもしれない(そして、説明を気にしないだろうなぜ彼らは脇の下として悪いのですか)。しかし、ベストプラクティスの範囲内にとどまることを目指して、私はそれらをサポートする図書館を引っ張らずに何かを解決する方法を見つけようとしており、私は立ち往生しています。

私は、React/ReduxアプリケーションでOpenLayersライブラリを使用してマップを作成しています。 OpenLayersでは、マップオブジェクトの作成時にマップを配置するためにDOM要素が必要です。したがって、コンポーネントがマウントされるまでOpenLayersマップをインスタンス化することはできません。それはいいです、それにはcomponentDidMountのライフサイクルフックがあります。

私が問題に遭遇するのは、そのマップオブジェクトを他のクラスに公開する必要があり、それらのクラスにマップが作成されるまで実行を待つ必要のあるコードがあることです。延期して、以下に示すように

、私はかなり単純にこれを扱うことができます:

const deferred = Q.defer(); 

const Foo = React.createClass({ 
    componentDidMount() { 
    const map = new ol.Map(...); 
    deferred.resolve(map); 
    } 
    ... 
} 

export getMap => deferred.promise 

は、しかし、ES6の約束で、私はこだわっています。

私はcomponentDidMountクラスの外で約束をインスタンス化することはできません。これは直ちに実行されるためです。

componentDidMount関数の範囲内で約束をインスタンス化する(または自分のコードが同期であるためPromise.resolveを使用する)場合、約束はgetMap関数の有効範囲外です。

promiseオブジェクトをcomponentDidMountのスコープの外部にインスタンス化しないと、getMapはcomponentDidMountが実行されるまでundefinedを返し、最初に約束を持つポイントを破棄します。

OpenLayersマップは非常に可変であり、独自のことをしているので、マップを置くと不変のReduxコミットメントが破られるので、私はそのマップをRedux状態にしません... so私はReduxソリューションを放棄しました。 "mapAvailable"のようなRedux状態で何らかのブール値を投げると、ハックのように感じます。私はおそらくその作業を行うことができますが、それは副次的な問題のホストを導入するでしょう。

私は何が欠けていますか?遅れが本当に正しい答えであるか、わかりません。

また、お時間をありがとうございます。

答えて

4

私はさらに、ブログで多くの人々がアンチパターンとしての使用を参照していることに驚きました。

あなたはDeferredの作り方の特定使い方についてである、ここでdeferred antipatternを参照するように見える - それはDeferredの作り方がアンチパターンであることを言っていません。

は、あなたがどんな繰延オブジェクトを必要としない、それにもかかわらず:-) deferreds are deprecatedが、resolve機能は絶対に十分です。

componentDidMountクラスの外に約束をインスタンス化することはできません。すぐに起動するためです。

なぜすぐに発射しますか?ただしないでください。あなたも、クラスのまわりでそれをラップすることができます:

export const promise = new Promise(resolve => { 
    const Foo = React.createClass({ 
    componentDidMount() { 
     const map = new ol.Map(…); 
     resolve(map); 
    } 
    … 
    } 
    … // do something with Foo here 
}); 

が、より多くの可能性が高いあなたは、これは恐ろしいパターンであることを当然の通知を

let resolve; 
export const promise = new Promise(r => { 
    resolve = r; 
}); 
export const Foo = React.createClass({ 
    componentDidMount() { 
    const map = new ol.Map(…); 
    resolve(map); 
    } 
    … 
} 

をしたくなります - あなただけのグローバルを作成しました静的約束、基本的にシングルトン。 Fooのいずれかのコンポーネントがマウントされると解決されます。それをしないでください。私はあなたのコンポーネントのコンストラクタに約束を置くことをお勧めしますが、私はあなたがそれが必要なものが何であるかまだまだわかりません。

+1

これは私の両方の質問を解決すると思います。私は適切に「解決する」ことを考えていませんでした。私はあなたの反応をライブで編集するのを見ています。あなたはそれについてもっと考えると思います。これが恐ろしいパターンかどうかという点では、アプリケーション内にFooコンポーネントが1つしかないため、シングルトンは比較的適切です。私が必要とするところでは、アプリケーション全体で他の多くのクラスがOpenLayersマップオブジェクトの唯一のコピーにアクセスする必要があります。それはまだ悪い決断のように見えますか? – JSager

+0

私はそう思う、それは 'Foo'シングルトンからの本質的なシングルトンとして約束を置くことはまだ悪い考えであろう - あなたのアプリでそれをインスタンス化するときはいつでも、マップのための約束はインスタンス化されるべきである。だからちょうどそれを 'Foo'の明白なプロパティにしてください – Bergi

+0

私がそれを予見するいくつかの問題です。まず、Reactが自分のコンポーネントをインスタンス化するときを制御することはできません。二番目に、私はReactコンポーネントをエクスポートしていません。 React-Reduxコンポーネントをエクスポートしていますが、これは私の問題に関係していないと思われるため含まれていませんでした。そして、Reactクラス全体を約束して新しいスコープの問題を作成します。最後に、私が最初に説明したように、マップを安全にインスタンス化する前に、ライフサイクルの「マウントされた」部分にヒットする必要があるため、Reactコンポーネントのコンストラクタにこの約束を置くことはできません。 – JSager

0

遅延がうまくいく場合がありますが、それらは古くなってしまい、遅延パターンの使用を禁止するパターンを見つけているのです。

延期が廃止されたという詳細については、this linkをご覧ください。

私はmapAvailableと同じ解決策を考え、ハックになることに同意します。あなたがこの状況に対してより良い解決策を見つけた場合は、お知らせください。

関連する問題