簡體   English   中英

React不提供遞歸的反應式組件

[英]React does not render recursive reactive components

鑒於此組件:

import React, { Component } from 'react';
import TrackerReact from 'meteor/ultimatejs:tracker-react';

export default class SubscriptionView extends TrackerReact(Component) {

  constructor(props) {
    super(props);

    let params = props.params || [];

    if (!Array.isArray(params)) {
      params = [params];
    }

    this.state = {
      subscription: {
        collection: Meteor.subscribe(props.subscription, ...params)
      }
    };
  }

  componentWillUnmount() {
    this.state.subscription.collection.stop();
  }


  render() {
    let loaded = this.state.subscription.collection.ready();

    if (!loaded) {
      return (
        <section className="subscription-view">
          <h3>Loading...</h3>
        </section>
      );
    }

    return (
      <section className="subscription-view">
        { this.props.children }
      </section>
    );
  }
};

還有另一個組成部分:

import SubscriptionView from './SubscriptionView.jsx';

export const Foo = () => (
  <SubscriptionView subscription="allFoo">
    <SubscriptionView subscription="singleBar" params={ 123 }>
      <div>Rendered!</div>
    </SubscriptionView>
  </SubscriptionView>
);

當數據可用時,第一個Subscription被重新渲染,但是第二個Subscription僅被渲染一次,僅此而已。 如果我放置一個console.log(this.props.subscription, ready); SubscriptionView的渲染功能中,我看到了

allFoo false
allFoo true
singleBar false

就是這樣。

在服務器端,兩種發布方法都是

Meteor.publish('allFoo', function () {
  console.log("Subscribing foos");
  return Foos.find();
});

Meteor.publish('singleBar', function (id) {
  console.log("Subscribing bar", id);
  return Bars.find({ _id: id });
});

兩種發布方法都被調用。

為什么第二個SubscriptionView沒有反應性?


*解決方案*

這是基於alexi2的評論:

import React, { Component } from 'react';
import TrackerReact from 'meteor/ultimatejs:tracker-react';

export default class SubscriptionLoader extends TrackerReact(Component) {

  constructor(props) {
    super(props);

    let params = props.params || [];

    if (!Array.isArray(params)) {
      params = [params];
    }

    this.state = {
      done: false,
      subscription: {
        collection: Meteor.subscribe(props.subscription, ...params)
      }
    };
  }

  componentWillUnmount() {
    this.state.subscription.collection.stop();
  }

  componentDidUpdate() {
    if (!this.state.done) {
      this.setState({ done: true });

      this.props.onReady && this.props.onReady();
    }
  }


  render() {
    let loaded = this.state.subscription.collection.ready();

    if (!loaded) {
      return (
        <div>Loading...</div>
      );
    }

    return null;
  }
};

然后,在父組件的render方法中:

<section className="inventory-item-view">
  <SubscriptionLoader subscription='singleBar' params={ this.props.id } onReady={ this.setReady.bind(this, 'barReady') } />
  <SubscriptionLoader subscription='allFoos' onReady={ this.setReady.bind(this, 'foosReady') } />
  { content }
</section>

其中setReady僅設置組件的狀態,並且僅當this.state.barReady && this.state.foosReady為true時, content才具有值。

有用!

嘗試像這樣分離出SubscriptionView組件:

import SubscriptionView from './SubscriptionView.jsx';

export const Foo = () => (
    <div>
      <SubscriptionView subscription="singleBar" params={ 123 }>
        <div>Rendered!</div>
      </SubscriptionView>
      <SubscriptionView subscription="allFoo">
        <div>Rendered Again!</div>
      </SubscriptionView>
    </div>
);

根據評論對話進行編輯

不確定我的路線是否正確,但是您可以將Foo構建為“智能”組件,並根據需要將道具傳遞給每個SubscriptionView,然后將Foo用作可重用組件。

假設我需要渲染的是FooBarForm,它需要在該特定用例中同時注冊Foos和Bars。 你會怎么做?

您可以創建按需使用道具的Components FoosBars ,並創建一個包含這些Components並傳遞必要數據的父組件FooBarForm

FooBarForm將處理狀態,並且隨着狀態的改變將其傳遞給其子組件的props。

現在狀態由父組件集中管理,子組件使用從父組件傳遞的道具進行渲染。

根據從父組件傳遞的狀態是否已更改,子組件將隨着其道具的更改而重新呈現。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM