6

これが慣用的な React ではないことはわかっていますが、レンダリング前とレンダリング後の両方でダウンストリームの仮想 DOM の変更を通知する必要がある React コンポーネント (逆スクロールビュー) に取り組んでいます。

これを説明するのは少し難しいので、出発点である JSFiddle を作成しました: https://jsfiddle.net/7hwtxdap/2/

私の目標は、ログを次のようにすることです。

Begin log

render

rendered small

rendered small

rendered small

before update

rendered big

after update

before update

rendered big

after update

before update

rendered big

after update

React が DOM の変更をバッチ処理することがあることは承知していますが、それで問題ありません (つまり、ログ イベントはbefore update; rendered big; rendered big; after update; ....


https://jsfiddle.net/7hwtxdap/4/で行うように、コールバックを指定することで手動で動作を近似できます。ただし、このアプローチはスケーリングしません。たとえば、子ではなく子孫からイベントをバブリングさせる必要があります。私が使用するすべてのコンポーネントにこれらの種類のイベント ハンドラーを追加する必要はありません。


使用事例:

メッセージ用の「逆スクロール コンポーネント」の作成に取り組んでいます (新しい要素が追加されたり、既存の要素のサイズが変更されたりすると、スクロール変更の基準は、すべてのメッセージング アプリの上部 ala ではなく、コンテンツの下部になります)。動的に変更された子があります (クラスに似てい<MyElement />ますが、高さが可変で、ajax からのデータなどがあります)。これらは、Flux のような状態ストアからデータを取得するのではなく、pub-sub データ同期モデルを使用しています (setTimeout() でかなりうまく近似されています)。

逆スクロールを機能させるには、次のようにする必要があります。

anyChildrenOfComponentWillUpdate() {
  let m = this.refs.x;
  this.scrollBottom = m.scrollHeight - m.scrollTop - m.offsetHeight;
}
anyChildrenOfComponentDidUpdate() {
  let m = this.refs.x;
  m.scrollTop = m.scrollHeight - m.offsetHeight - this.scrollBottom;
}

この設計にとって重要なのは、「反転スクロール対応」ではない他の要素の周りに要素をラップできるようにすることです (つまり、反転スクロール ハンドラーに変更されたことを通知する特別なコードは必要ありません)。

4

4 に答える 4

1

ジェームズが言ったように、コンテキストを使用して、すべての子孫コンポーネントに渡すことができるコールバック関数を定義できます。コンポーネントを拡張したくない場合は、デコレータを使用して高次コンポーネントをそれらの周りにラップできます。このようなもの:

コンテナー内:

class Container extends React.Component {
    static childContextTypes =  {
        log: React.PropTypes.func.isRequired
    };

   getChildContext() {
      return {
            log: (msg) => {
                console.log(msg)
            }
        }
    }

  render() {
    console.log("Begin Log")
    return (
        <div>
          <MyElement />
          <MyElement />
          <MyElement />
        </div>
    );
  }
}

デコレータ クラス:

export const Logger = ComposedComponent => class extends React.Component {
    static contextTypes = {
        log: React.PropTypes.func.isRequired
    };

    constructor(props) {
        super(props)
    }

    componentWillReceiveProps(nextProps) {
        this.context.log('will receive props');
    }

    componentWillUpdate() {
        this.context.log('before update');
    }

    componentDidUpdate() {
        this.context.log('after update');
    }

  render() {
      return <ComposedComponent {...this.props}/>
  }
} 

次に、必要なコンポーネントを装飾します

@Logger
class MyElement extends React.Component {
...
}
于 2016-06-26T17:48:15.833 に答える