Reputation: 2712
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?
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()
?
Upvotes: 2
Views: 336
Reputation: 131
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.
Upvotes: 1
Reputation: 6379
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:
Upvotes: 2