V
V
Vanya Huk2018-09-27 20:07:42
React
Vanya Huk, 2018-09-27 20:07:42

Why is render executed before componentWillMount?

there is a component:

import React, {Component} from 'react';
import {connect} from 'react-redux';
import {bindActionCreators} from "redux";
import FilterModels from './FilterModels';
import {getTypes} from '../../actions/AjaxDataActions';

class FilterForm extends Component {

  constructor(props) {

    super(props);

  }

  async componentWillMount(){

               console.log( 1 );
    await this.props.getTypes(this.props.params, this.props.api) ;
    console.log( 2 );

  }


  render() {

    console.log( 3 )

    return (
      <div>
        <FilterModels/>
      </div>
    )
  }
}

function matchDispatchToProps(dispatch) {

  return bindActionCreators({
    getTypes: getTypes
  }, dispatch);
}

export default connect(
  state => ({
    api: state.api,
    params: state.ajaxData
  }), matchDispatchToProps)(FilterForm);

action code :
export const getTypes = (object, api) => {
  return async dispatch => {
    await axios.post(api.url + api.transports + '/' + api.type)
      .then(response => {
        dispatch({
          type: UPDATE_AJAX_PARAMS,
          payload: response.data
        });
      });
  }

};

according to the idea console.log should draw 1->2->3, but in practice - 1,3,2
Question - what is wrong with the code and how to fix it?

Answer the question

In order to leave comments, you need to log in

2 answer(s)
A
Anton Spirin, 2018-09-27
@vanyahuk

Because the library does not expect the return value in componentWillMount and then immediately calls render.
Forget this method - it is not recommended for use. As mentioned above, asynchronous requests are recommended to be initiated in componentDidMount. It is executed after the render call, which you want to avoid for some obscure reason.
Here are two solutions:
1. Before loading data, return null to render or preloader.

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

   if (!data) return null;
     
    return (
      <div>
        <FilterModels />
      </div>
    )
  }
}

2. Move the data loading to the parent component and render the target by condition:
render() {
  const { filterData } = this.props;
  return (
    <Wrapper>
      {filterData  && <FilterForm data={filterData} />}
   </Wrapper>
  )
}

N
Nikita Trofimov, 2018-09-27
@trofProg

Loading via api is best done in componentDidMount, and changing states in it, you can read about this in the documentation https://reactjs.org/docs/react-component.html#comp... . componentWillMont is already deprecated, instead of it you can do everything in the constructor (defanite states and bind functions). Logs are executed correctly. If you were to throw props into the component and they would change, then 3 would be executed again. If the rendering of the component was waiting for the api to load, then we would have to wait a long time until the component appears. The component appears without delay, it just re-renders later if the states it uses change

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question