[解決済み】Reduxで非同期アクションを実行するモーダルダイアログを表示するにはどうすればよいですか?
質問
ある状況下で確認ダイアログを表示する必要があるアプリを作成しています。
例えば、何かを削除したい場合、次のようなアクションをディスパッチします。
deleteSomething(id)
そのため、いくつかのreducerがそのイベントをキャッチし、それを表示するためにダイアログreducerを埋めることになります。
私の疑問は、このダイアログが送信されるときです。
- このコンポーネントは、最初にディスパッチされたアクションに応じて、どのように適切なアクションをディスパッチすることができますか?
- このロジックは、アクションクリエイターが処理すべきですか?
- reducerの内部にアクションを追加することは可能か?
を編集します。
を追加し、より分かりやすくしました。
deleteThingA(id) => show dialog with Questions => deleteThingARemotely(id)
createThingB(id) => Show dialog with Questions => createThingBRemotely(id)
そこで、ダイアログコンポーネントを再利用しようと思っています。ダイアログの表示/非表示は、リデューサで簡単に行えるので問題ではありません。私が指定しようとしているのは、左側でフローを開始するアクションに従って、右側からアクションをディスパッチする方法です。
どのように解決するのですか?
更新情報
: React 16.0からポータルが導入されました。
ReactDOM.createPortal
リンク
更新情報
React の次のバージョン(繊維:おそらく 16 または 17)には、ポータルを作成するメソッドが含まれる予定です。
ReactDOM.unstable_createPortal()
リンク
ポータルサイトの利用
Dan Abramov回答最初の部分は良いのですが、多くの定型文が含まれています。彼が言ったように、ポータルを使うこともできます。そのアイデアについて、もう少し詳しく説明します。
ポータルの利点は、ポップアップとボタンがReactツリーに非常に近いまま、propsを使用して非常にシンプルな親子通信を行うことです。ポータルで非同期アクションを簡単に処理したり、親にポータルをカスタマイズさせたりすることが可能です。
ポータルとは何ですか?
ポータルを使用すると
document.body
Reactツリー内に深くネストされた要素です。
例えば、以下のようなReactツリーをbodyにレンダリングするということです。
<div className="layout">
<div className="outside-portal">
<Portal>
<div className="inside-portal">
PortalContent
</div>
</Portal>
</div>
</div>
そして、出力として得られます。
<body>
<div class="layout">
<div class="outside-portal">
</div>
</div>
<div class="inside-portal">
PortalContent
</div>
</body>
は
inside-portal
ノードの内部で翻訳されています。
<body>
を、通常の深いネストの場所ではなく、"left" と呼びます。
ポータルを使用する場合
ポータルは、ポップアップ、ドロップダウン、サジェスト、ホットスポットなど、既存のReactコンポーネントの上に置くべき要素を表示する場合に特に便利です。
ポータルを使用する理由
z-indexの問題はもうない
へのレンダリングが可能です。
<body>
. ポップアップやドロップダウンを表示する場合、z-indexの問題と戦う必要がないのであれば、これは本当にいいアイデアです。ポータル要素は、以下のように追加されます。
document.body
をマウント順に並べるということです。
z-index
の場合、デフォルトの動作は、ポータルをマウント順に重ねることになります。実際には、これは他のポップアップの中からポップアップを安全に開くことができ、2番目のポップアップが最初のポップアップの上に表示されることを保証することを意味します。
z-index
.
実践編
最もシンプル:ローカルなReactの状態を使用する。 もし、単純な削除確認ポップアップのために、Reduxのボイラープレートを持つ価値がないと思うなら、ポータルを使うことができ、コードを大幅に単純化することができます。このようなユースケースでは、インタラクションは非常にローカルで、実際にはかなり細かいところまで実装されています。ホットロード、タイムトラベリング、アクションログなど、Reduxがもたらすすべての利点を本当に気にする必要がありますか?個人的には、私はそうではなく、このような場合にはローカルステートを使用します。コードは次のようにシンプルになります。
class DeleteButton extends React.Component {
static propTypes = {
onDelete: PropTypes.func.isRequired,
};
state = { confirmationPopup: false };
open = () => {
this.setState({ confirmationPopup: true });
};
close = () => {
this.setState({ confirmationPopup: false });
};
render() {
return (
<div className="delete-button">
<div onClick={() => this.open()}>Delete</div>
{this.state.confirmationPopup && (
<Portal>
<DeleteConfirmationPopup
onCancel={() => this.close()}
onConfirm={() => {
this.close();
this.props.onDelete();
}}
/>
</Portal>
)}
</div>
);
}
}
シンプル:まだReduxの状態を使用することができます
を使用することができます。
connect
を使用するかどうかを選択するために
DeleteConfirmationPopup
を表示するかどうかを決定します。ポータルはReactツリーに深くネストしたままなので、親がポータルにpropを渡すことができ、このポータルの動作をカスタマイズするのは非常に簡単です。ポータルを使用しない場合、通常、ポップアップをReactツリーの最上位でレンダリングする必要があります。
z-index
のような理由で、通常、「ユースケースに応じて構築した汎用的な DeleteConfirmationPopup をどのようにカスタマイズするか」ということを考えなければなりません。例えば、ネストしたconfirm/cancelアクションを含むアクションをディスパッチしたり、翻訳バンドルキーや、さらに悪いことにレンダー関数(またはシリアル化できない何か)をディスパッチするような、この問題に対する非常に陳腐な解決策が見つかることがあります。ポータルではそのようなことをする必要はなく、通常のプロップを渡すだけでよいのです。
DeleteConfirmationPopup
の単なる子です。
DeleteButton
結論
ポータルは、コードを簡素化するのにとても便利です。私はもうこれなしではやっていけません。
ポータルの実装は、次のような他の便利な機能にも役立ちますので、注意してください。
- アクセシビリティ
- ポータルを閉じるためのEspaceショートカット
- 外部クリックの処理(ポータルを閉じるかどうか)
- リンククリックの処理(ポータルを閉じるか否か)
- ポータルツリーでReact Contextを利用可能に
react-portal または リアクトモーダル は、フルスクリーンで表示されるポップアップ、モーダル、オーバーレイに適しており、一般に画面の中央に配置されます。
リアクトテザー
は、ほとんどのReact開発者に知られていませんが、最も便利なツールの一つです。
テザー
は、ポータルを作成することを許可しますが、与えられたターゲットからの相対位置で、ポータルを自動的に配置します。これは、ツールチップ、ドロップダウン、ホットスポット、ヘルプボックスなどに最適です。もしあなたが、ポータルの位置決めに関して何らかの問題を抱えているのであれば
absolute
/
relative
と
z-index
ドロップダウンがビューポートの外に出てしまうような場合、Tetherがすべてを解決してくれます。
例えば、クリックするとツールチップに展開するオンボーディングホットスポットを簡単に実装することができます。
ここからが本当のプロダクションコードです。これ以上シンプルなものはないでしょう :)
<MenuHotspots.contacts>
<ContactButton/>
</MenuHotspots.contacts>
編集 を発見しました。 リアクトゲートウェイ これは、ポータルを好きなノードにレンダリングすることを許可するものです(必ずしもボディとは限りません)。
編集 : どうやら リアクトポッパー は、react-tetherの代替品となり得ます。 ポッパーJS は、DOMに直接触れることなく、要素の適切な位置だけを計算するライブラリで、Tetherがbodyに直接追加するのに対して、DOMノードを置きたい場所とタイミングをユーザーに選択させることができます。
編集 もあります。 リアクトスロットフィル これは興味深いもので、ツリーの好きな場所に配置した予約済み要素スロットに要素をレンダリングすることで、同様の問題を解決することができます。
関連
-
[解決済み】Failed to load resource: net::ERR_FILE_NOT_FOUND loading json.js
-
[解決済み】フォームコントロールの値アクセサがない
-
[解決済み】Javascriptのコールバック関数がFirefoxで「Callback is not a function」というエラーを投げる
-
[解決済み】SyntaxError: ChromeのJavascriptコンソールでUnexpected Identifierが発生する。
-
[解決済み】このオブジェクトの "forEach "はなぜ関数でないのですか?
-
[解決済み】Uncaught TypeError: 未定義のプロパティ 'msie' を読み取れない - jQuery tools
-
[解決済み】JavaScriptで関数が存在するかどうかを確認する方法は?
-
[解決済み] JavaScriptのオブジェクトを表示するにはどうすればよいですか?
-
[解決済み] どうすればjQueryに非同期ではなく、同期のAjaxリクエストを実行させることができますか?
-
[解決済み] Reduxの非同期フローになぜミドルウェアが必要なのか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] Uncaught TypeError: 未定義のプロパティ 'top' を読み込めない
-
[解決済み] 解決済み】clearInterval()が動作しない [重複] [重複]
-
[解決済み】JavaScriptのgetElementByNameが機能しない
-
[解決済み】SyntaxError: 'import' と 'export' は 'sourceType: module' とだけ表示されるかもしれない - Gulp
-
[解決済み] エラー。モジュールhtmlが見つからない
-
[解決済み】getElementByIdはnullを返す?[クローズド]
-
[解決済み】Redux TypeError: 未定義のプロパティ 'apply' を読み取れない
-
[解決済み】react router v^4.0.0 Uncaught TypeError: 未定義のプロパティ'location'を読み取れない
-
[解決済み] Uncaught (in promise) TypeError: フェッチに失敗してCorsエラー
-
[解決済み】ReactJS 2つのコンポーネントが通信しています。