最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Why componentWillMount is called after rendering? - Stack Overflow

programmeradmin3浏览0评论

I am working with React and I am trying to understand the lifecycle. I am doing a ponentWillMount method in order to get the props I need before the render occurs. I need to know how to update the state when the view loads.

All I am trying to do is a GET request in order to get a list of dealers for a Casino Game. Basically, I am missing 1 or 2 steps which are for render the dealers's list in the DOM

I will show what I am doing with my code and after that I will explain what I want

Actions part

getDealerActions.js

class GetDealersActions {

  constructor () {
    this.generateActions('dealerDataSuccess', 'dealerDataFail');
  }

  getDealers (data) {
    const that = this;
    that.dispatch();
    axios.get('someroute/get-dealers/get-dealers')
      .then(function success (response) {
        that.actions.dealerDataSuccess({...response.data});
      })
  }
};

then we move to the stores

getDealersStore.js

class GetDealersStore {

  constructor () {
    this.state = {
      dealerData : null,
    };
  }

  @bind(GetDealersActions.dealerDataSuccess)
  dealerDataSuccess (data) {
    this.setState({
      dealerData : data,
    });
   console.log(this.state.dealerData);
  }
}

in this case that console.log(this.state.dealerData); returns something like this which is exactly what I need

Object {dealersData: Array[3]}

the problems es in the ponent part, honestly because I don't know how to handle the data here

@connectToStores
export default class Dealers extends Component {

  static contextTypes = {
    router : React.PropTypes.func,
  }

  constructor (props) {
    super(props);
    this.state = {}
  }

  static getStores () {
    return [ GetDealersStore ];
  }

  static getPropsFromStores () {
    return GetDealersStore.getState();
  }

  ponentWillMount () {
    console.log('@@@', this.props);
    GetDealersActions.getDealers();
  }

  render () {
    console.log('>>>', this.props);
    let content;
    if (this.state.dealerData) {
      content = this.state.dealerData.map((item) => {
        return <div key={item.CardId}>{item}</div>;
      });
    } else {
      content = <div>Loading . . .</div>;
    }

    return (
      <div>
        <div>{content}</div>
      </div>
    );
  }

}

all I get here <div>{content}</div> is Loading . . . because this.state is ing like this Object {}

A weird situation I am getting here, is that this view is rendering twice, the 1st time is rendering, and the console.log('>>>', this.props); returns this >>> Object {params: Object, query: Object} and the second time it renders, fires this >>> Object {params: Object, query: Object, dealerData: Object} which is what I need.

So, why ponentWillMount is waiting the render method in order to get fired ?

I am working with React and I am trying to understand the lifecycle. I am doing a ponentWillMount method in order to get the props I need before the render occurs. I need to know how to update the state when the view loads.

All I am trying to do is a GET request in order to get a list of dealers for a Casino Game. Basically, I am missing 1 or 2 steps which are for render the dealers's list in the DOM

I will show what I am doing with my code and after that I will explain what I want

Actions part

getDealerActions.js

class GetDealersActions {

  constructor () {
    this.generateActions('dealerDataSuccess', 'dealerDataFail');
  }

  getDealers (data) {
    const that = this;
    that.dispatch();
    axios.get('someroute/get-dealers/get-dealers')
      .then(function success (response) {
        that.actions.dealerDataSuccess({...response.data});
      })
  }
};

then we move to the stores

getDealersStore.js

class GetDealersStore {

  constructor () {
    this.state = {
      dealerData : null,
    };
  }

  @bind(GetDealersActions.dealerDataSuccess)
  dealerDataSuccess (data) {
    this.setState({
      dealerData : data,
    });
   console.log(this.state.dealerData);
  }
}

in this case that console.log(this.state.dealerData); returns something like this which is exactly what I need

Object {dealersData: Array[3]}

the problems es in the ponent part, honestly because I don't know how to handle the data here

@connectToStores
export default class Dealers extends Component {

  static contextTypes = {
    router : React.PropTypes.func,
  }

  constructor (props) {
    super(props);
    this.state = {}
  }

  static getStores () {
    return [ GetDealersStore ];
  }

  static getPropsFromStores () {
    return GetDealersStore.getState();
  }

  ponentWillMount () {
    console.log('@@@', this.props);
    GetDealersActions.getDealers();
  }

  render () {
    console.log('>>>', this.props);
    let content;
    if (this.state.dealerData) {
      content = this.state.dealerData.map((item) => {
        return <div key={item.CardId}>{item}</div>;
      });
    } else {
      content = <div>Loading . . .</div>;
    }

    return (
      <div>
        <div>{content}</div>
      </div>
    );
  }

}

all I get here <div>{content}</div> is Loading . . . because this.state is ing like this Object {}

A weird situation I am getting here, is that this view is rendering twice, the 1st time is rendering, and the console.log('>>>', this.props); returns this >>> Object {params: Object, query: Object} and the second time it renders, fires this >>> Object {params: Object, query: Object, dealerData: Object} which is what I need.

So, why ponentWillMount is waiting the render method in order to get fired ?

Share Improve this question asked Oct 8, 2015 at 20:31 NonNon 8,59920 gold badges80 silver badges130 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 7

It's not weird at all. ponentWillMount will fire before render, and in the first-pass you are invoking an action to get the dealers GetDealersActions.getDealers(); which is basically an async mand. Since it is async, the ponent will render once before it gets data, and then again after the store publishes a changed event, which will re-trigger rendering.

Here is an approximation of the sequence of actions happening in your example:

  1. ponentWillMount invokes getDealers mand (which is async)
  2. initial render with default ponent state
  3. Async operation pleted in action creator and store is set with dealer data
  4. store publishes a changed event, which re-triggers rendering
  5. second render invoked with the dealer data in ponent state.

The problem is that React will run it's lifecycle methods in a certain sequence, not caring about you invoking some async method. So basically you don't have a way to stop rendering just because you invoked a mand to get the dealers. That is a limitation of react (or a feature), which surfaces when bined with async programming and you should accept it as is.

If you accept the fact that React will render twice, you can utilize that in your favor, so on first render you could just show a loading indicator (e.g. a spinning wheel) and when the data loads you just display it in the second render.

However, if you are not convinced and still want to avoid double-rendering in the initial load, you could do prefetching of the data before you mount the application ponent, which would ensure that initial data is loaded in the store before the first render, which would mean that you wouldn't have to invoke getDealers in ponentWillMount since the data would already be in the store on the first render.

As a reminder, double-rendering is not a significant performance problem, like it would be in Angular.js or Ember.js, since React is very efficient at DOM manipulation, but it could produce some UX issues if not handled properly.

发布评论

评论列表(0)

  1. 暂无评论