javascript 如何在加载数据之前阻止组件呈现?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/33131542/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-28 16:09:07  来源:igfitidea点击:

How can I prevent a component from rendering before data is loaded?

javascriptreactjs

提问by Non

I am waiting the props to come up from a store named GetDealersStore, and the way I am fetching that data is with an action where I am doing this:

我正在等待道具从名为 的商店中出来GetDealersStore,而我获取数据的方式是通过一个动作来执行此操作:

  componentWillMount () { GetDealersActions.getDealers(); }

I already test the app and componentWillMount()is running before the initial render where I have this

我已经测试了该应用程序并componentWillMount()在我拥有此应用程序的初始渲染之前运行

let dealerInfo;
if (this.state.dealerData) {
  dealerInfo = this.state.dealerData.dealersData.map((dealer) => {
    return (<div>CONTENT</div>);
  })
} else {
  dealerInfo = <p>Loading . . .</p>
}

but for the first second you can see <p>Loading . . .</p>in the screen which is the elsein the conditional above, and then the rest of the render comes up with return (<div>CONTENT</div>);which is the ifin the conditional. So, I guess, this means that the render method has been trigger twice because it keeps waiting for the data coming from the database.

但对于第一第二,你可以看到<p>Loading . . .</p>在这是在屏幕else的上面的条件,再渲染其余想出了return (<div>CONTENT</div>);这是if在有条件的。所以,我猜,这意味着渲染方法已经被触发两次,因为它一直在等待来自数据库的数据。

The data from the database is not available at the time of the 1st render, so, how can I fetch that data before the 1st initial render occurs?

数据库中的数据在第一次渲染时不可用,那么,如何在第一次初始渲染发生之前获取该数据?

回答by Mathletics

You can't do this with a single component. You should follow the Container Componentpattern to separate data from rendering.

您无法使用单个组件执行此操作。您应该遵循容器组件模式将数据与渲染分开。

let DealersContainer = React.createClass({
  getInitialState() {
    return {dealersData: []};
  },
  componentWillMount() {
    GetDealersActions.getDealers();
  },
  render() {
    let {dealersData} = this.state;
    return (<div>
      {dealersData.map((dealer) => {
        let props = dealer;
        return (<Dealer ...props />); // pass in dealerData as PROPS here
      })}
    </div>);
  }
});

Then update your Dealercomponent to receive props and render the actual content.

然后更新您的Dealer组件以接收道具并呈现实际内容。

回答by Oliver Fencott

My answer is similar to Mathletics', just in more detail.

我的回答与 Mathletics 类似,只是更详细一些。

In this example I've included initialising state of dealerData to null; this is the check that's made to determine whether the data has been returned from the store by the container.

在这个例子中,我包括了将 DealerData 的初始化状态设置为 null;这是用于确定数据是否已由容器从存储返回的检查。

It's verbose, but declarative, and does what you want, in the order that you want, and it will work each time.

它很冗长,但具有声明性,并且按照您想要的顺序执行您想要的操作,并且每次都可以使用。

const DealerStore = MyDataPersistenceLibrary.createStore({
  getInitialState() {
    return {
      dealerData: null
    };
  },

  getDealers() {
    // some action that sets the dealerData to an array
  }
});

const DealerInfoContainer = React.createClass({
  componentWillMount() {
    DealerStoreActions.getDealers();
  },

  _renderDealerInfo() {
    return (
      <DealerInfo {...this.state} />
    );
  },

  _renderLoader() {
    return (
      <p>Loading...</p>
    );
  },

  render() {
    const { dealerData } = this.state;

    return (
      dealerData
      ? this._renderDealerInfo()
      : this._renderLoader()
    );
  }
});

const DealerInfo = React.createClass({
  getDefaultProps() {
    return {
      dealerData: []
    };
  },

  _renderDealers() {
    const { dealerData } = this.props;

    return dealerData.map(({ name }, index) => <div key={index}>{name}</div>);
  },

  _renderNoneFound() {
    return (
      <p>No results to show!</p>
    );
  },

  render() {
    const { dealerData } = this.props;

    return (
      dealerData.length 
      ? this._renderDealers()
      : this._renderNoneFound()
    );
  }
});