2

I'm learning RN with Udemy: The Complete React Native and Redux Course by Stephen Grider and i'm creating a managing app with Firebase.

I have my connect function from react-redux library and have mapStateToProps() so every time i have changes in my states, i will receive them as props in my component.

I created an action to fetch data from Firebase database and i'm going to call it in the componentWillMount() but since fetching data is an async task, i have to create my data source in the componentWillReceiveProps().

But instructor said i have to call my createDataSource() in both componentWillMount() and componentWillReceiveProps() .

I can't understand why!! if i have any changes in the states (which here is my employees list), i will receive them as props, so i think it's enough to call createDataSource() in componentWillReceiveProps() only.

Can anyone declare that for me please? Is there any special case that i'm forgetting to handle?

UPDATE

EmployeeActions.js:

export const employeesFetch = () => {
  const { currentUser } = firebase.auth();

  return dispatch => {
    firebase
      .database()
      .ref(`/users/${currentUser.uid}/employees`)
      .on("value", snapshot => {
        dispatch({ type: EMPLOYEES_FETCH_SUCCESS, payload: snapshot.val() });
      });
  };
};

EmployeeList.js:

  componentWillMount() {
    this.props.employeesFetch();

    this.createDataSource(this.props);
  }

  componentWillReceiveProps(nextProps) {
    this.createDataSource(nextProps);
  }

  createDataSource({ employees }) {
    const ds = new ListView.DataSource({
      rowHasChanged: (r1, r2) => r1 !== r2
    });

    this.dataSource = ds.cloneWithRows(employees);
  }

so i'm using ListView to show my fetched employees from Firebase! Will i have any problem if i just use createDataSource() in the componentWillReceiveProps()?

7
  • Could you post some code? It is hard to follow what you mean. From reading you, I would say A) Reducers shouldn't fetch data B) componentWillReceiveProps (which I believe is deprecated) sounds like the method you should use C) try to use Functional components as much as possible with Redux and D) User redux-thunk to handle asycn actions Commented Jun 5, 2018 at 16:05
  • @PabloBarríaUrenda code added. A) was a typo, i meant actions B) so any other way to do that? Commented Jun 5, 2018 at 16:45
  • B) reactjs.org/docs/… Commented Jun 5, 2018 at 16:59
  • E) What is createDataSource? is that a Firebase specific thing? Commented Jun 5, 2018 at 17:00
  • 1
    unfortunately, Stephen Grider's classes at Udemy are so outdated that they are useles nowadays. And author is not responding to questions from user to update the classes for more than a year now. Lots of material, APIs, methods, tools he uses are irrelevant now in 2019. But I agree, they were very good in 2017, and early 2018 Commented May 23, 2019 at 13:02

2 Answers 2

2

I have also completed the Udemy course you mentioned, and first of all I have to say that using componentWillReceiveProps() and componentWillMount() props are being deprecated and should no longer be used. In new projects you are advised to use static getDerivedStateFromProps() and componentDidUpdate(). The official React docs will give you additional information on this topic.

But componentWillReceiveProps() is only called after the initial render has been completed, so if your component does not receive the props on instantiation you need to do the setup in componentWillMount().

Edit If you want to adhere to new best practices this would be the way to go:

  • Do any instantiation in the constructor
  • Async setup needs to go in componentDidMount()
  • static getDerivedStateFromProps() is called before every render, (initial render and re-renders because of updates)
  • componentDidUpdate() is called on props updates after initial render
Sign up to request clarification or add additional context in comments.

7 Comments

tnx for first part - second part: so after the initial render (and if i have update in states so i have them as props) the helper function createDataSource() will be called two times? one time in componentWillMount() since i'm navigating to that scene and second time in componentWillReceiveProps() because i've new props! am i right?
componentWillMount is called before the initial render, but if you are sure the component receives an up to date datasource in it's constructor you will indeed not need componentWillMount
Actually the reason componentWillMount is deprecated is because many people were doing async actions here, which could defer rendering and lead to a decrease in perceived performance
tnx for your description - just one thing that i didn't understand yet is if i use the Stephen's way, i will call createDataSource() twice?
Normally it should be called only once
|
1

I also did the same Udemy course and was in the process of refactoring code after I read that some React lifecycles are being deprecated and replaced by different ones.

this is my old logic of fetching and updating:

    state = { dataSource: [] }

    componentWillMount() {
      const { userCentres } = this.props;

      this.props.fetchCentres(userCentres);
      this.createDataSource(this.props);
    }

    componentWillReceiveProps(nextProps) {
      this.createDataSource(nextProps);
    }

    createDataSource({ centresList }) {
      this.setState({ dataSource: centresList });
    }

I tried replacing my current logic using static getDerivedStateFromProps but I had issues with it since I could not use the keyword this inside it's scope which means I could not call this.createDataSource(props) from it. I also read "you probably don't need derived state" and after that decided it's much better to use getSnapshotBeforeUpdate and componentDidUpdate instead.

getSnapshotBeforeUpdate() is invoked right before the most recently rendered output is committed to e.g. the DOM. It enables your component to capture some information from the DOM (e.g. scroll position) before it is potentially changed. Any value returned by this lifecycle will be passed as a parameter to componentDidUpdate().

this is how I refactored my code:

      state = { dataSource: [] }

      componentDidMount() {
        const { userCentres } = this.props;

        this.props.fetchCentres(userCentres);
      }

      componentDidUpdate(prevProps, prevState, snapshot) {
        if (snapshot) {
          this.createDataSource(this.props);
        }
      }

      getSnapshotBeforeUpdate(prevProps) {
        if (prevProps.centresList !== this.props.centresList) {
          return true;
        }

        return null;
      }

      createDataSource({ centresList }) {
        this.setState({ dataSource: centresList });
      }

This ended up working for me even though I'm not 100% sure this is the best way of solving the problem. I should also note this is a PureComponent.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.