web-dev-qa-db-ja.com

内部状態を失わずにReactJSコンポーネントを表示/非表示しますか?

私は、反応しないコンポーネントをレンダリングしないことで非表示/表示しています。例えば:

render: function() {
  var partial;
  if (this.state.currentPage === 'home') {
    partial = <Home />;
  } else if (this.state.currentPage === 'bio') {
    partial = <Bio />;
  } else {
    partial = <h1>Not found</h1>
  }
  return (
    <div>
      <div>I am a menu that stays here</div>
      <a href="#/home">Home</a> <a href="#/bio">Bio</a>
      {partial}
    </div>
  );
}

ただし、<Bio/>コンポーネントには多くの内部状態があるとだけ言ってください。コンポーネントを再作成するたびに、内部状態が失われ、元の状態にリセットされます。

もちろん、データをどこかに保存し、小道具で渡すか、単にグローバルにアクセスできることを知っていますが、このデータはコンポーネントの外部に存在する必要はありません。 CSS(display:none)を使用してコンポーネントを非表示/表示することもできますが、上記のようにコンポーネントを非表示/表示したいと思います。

ここでのベストプラクティスは何ですか?

編集:たぶん問題を述べるより良い方法は例を使用することです:

Reactを無視し、1と2という名前の2つのタブを持つAと呼ばれるタブコンポーネントを備えた構成ダイアログを備えたデスクトップアプリを使用していると仮定します。

タブA.1にメールテキストフィールドがあり、メールアドレスを入力するとします。次に、タブA.2をクリックしてから、タブA.1に戻ります。何が起こったか?あなたのメールアドレスはもう存在しません。内部状態はどこにも保存されていないため、何もリセットされていません。

状態の内部化は、以下の回答の1つで提案されているように機能しますが、コンポーネントとその直接の子に対してのみです。コンポーネントを他のコンポーネント(タブ内のタブ内のタブなど)に任意にネストしている場合、内部状態を保持する唯一の方法は、どこかで外部化するか、実際にすべての子を保持するdisplay:noneアプローチを使用することです常に周囲のコンポーネント。

このタイプのデータは、アプリの状態を汚したいデータではないように思えます...あるいは、考えさえしなければならないデータです。親コンポーネントレベルで制御でき、display:noneアプローチを使用せず、保存方法の詳細を考慮することなく、保持または破棄を選択できるデータのようです。

24
Brad Parks

1つのオプションは、コンポーネント自体の内部で条件を移動することです。

Bio = React.createClass({
    render: function() {
        if(this.props.show) {
            return <p>bio comp</p>
        } else {
            return null;
        }
    }
});

<Bio show={isBioPage} />

これが「ベストプラクティス」であるかどうかは、おそらく正確な状況に依存します。

10
Colin Ramsay

残念ながら、style={{display: 'none'}}トリックは、通常のDOM要素でのみ機能し、Reactコンポーネント。コンポーネントをdiv内にラップする必要があります。したがって、サブコンポーネントに状態をカスケードする必要はありません。

<div className="content">
  <div className={this.state.curTab == 'securities' ? 'active' : ''}>
    <Securities />
  </div>
  <div className={this.state.curTab == 'plugins' ? 'active' : ''}>
    <Plugins />
  </div>
</div>
6
osamu

公式ドキュメントが示唆する ステートフルな子をstyle={{display: 'none'}}で隠す

3
nilgun

ここでの基本的な問題は、Reactでは、コンポーネントをその親にのみマウントできることです。これは、常に望ましい動作ではありません。しかし、この問題に対処する方法は?

この問題を解決するための解決策を提案します。より詳細な問題定義、src、および例はここにあります: https://github.com/fckt/react-layer-stack#rationale

根拠

react/_react-dom_には、2つの基本的な仮定/アイデアがあります。

  • すべてのUIは自然に階層的です。これが、互いにラップするcomponentsのアイデアがある理由です
  • _react-dom_は、デフォルトで(物理的に)子コンポーネントをその親DOMノードにマウントします

問題は、場合によっては、2番目のプロパティがあなたの望むものではないことです。コンポーネントを異なる物理DOMノードにマウントし、同時に親と子の間の論理接続を保持したい場合があります。

正規の例はツールチップのようなコンポーネントです:開発プロセスのある時点で、_UI element_の説明を追加する必要があることがわかります:固定レイヤーでレンダリングされ、その座標(_UI element_ coordまたはmouse coords)および同時に表示する必要があるかどうかの情報、その内容、および親コンポーネントのコンテキストが必要です。この例は、論理階層が物理DOM階層と一致しない場合があることを示しています。

https://github.com/fckt/react-layer-stack/blob/master/README.md#real-world-usage-example を見て、答えである具体例を確認してくださいあなたの質問に(「use」プロパティを見てください):

_import { Layer, LayerContext } from 'react-layer-stack'
// ... for each `object` in array of `objects`
  const modalId = 'DeleteObjectConfirmation' + objects[rowIndex].id
  return (
    <Cell {...props}>
        // the layer definition. The content will show up in the LayerStackMountPoint when `show(modalId)` be fired in LayerContext
        <Layer use={[objects[rowIndex], rowIndex]} id={modalId}> {({
            hideMe, // alias for `hide(modalId)`
            index } // useful to know to set zIndex, for example
            , e) => // access to the arguments (click event data in this example)
          <Modal onClick={ hideMe } zIndex={(index + 1) * 1000}>
            <ConfirmationDialog
              title={ 'Delete' }
              message={ "You're about to delete to " + '"' + objects[rowIndex].name + '"' }
              confirmButton={ <Button type="primary">DELETE</Button> }
              onConfirm={ this.handleDeleteObject.bind(this, objects[rowIndex].name, hideMe) } // hide after confirmation
              close={ hideMe } />
          </Modal> }
        </Layer>

        // this is the toggle for Layer with `id === modalId` can be defined everywhere in the components tree
        <LayerContext id={ modalId }> {({showMe}) => // showMe is alias for `show(modalId)`
          <div style={styles.iconOverlay} onClick={ (e) => showMe(e) }> // additional arguments can be passed (like event)
            <Icon type="trash" />
          </div> }
        </LayerContext>
    </Cell>)
// ...
_
2
fckt