I am trying to fetch some data from an API call. I am using getDerivedStateFromProps, componentDidMount,shouldComponentUpdateandcomponentDidUpdate`.
I am doing it like this because I need userToken which comes from userToken: store.signinScreen.userToken to be there before the call of the function GetPassengersData which needs userToken to get the data from the API.
This is the whole component:
// imports
class HomeScreen extends Component {
static navigationOptions = {
header: null,
};
state = {
error: false,
};
static getDerivedStateFromProps(props, state) {
if (props.userToken !== state.userToken) {
return { userToken: props.userToken };
}
return null;
}
componentDidMount() {
this.GetPassengersData();
}
shouldComponentUpdate(prevProps, state) {
return this.props !== prevProps;
}
componentDidUpdate(prevProps, prevState) {
const { error } = this.state;
if (!error) {
this.GetPassengersData();
}
}
GetPassengersData = async () => {
const { passengersDataActionHandler, userToken } = this.props;
if (userToken && userToken !== null) {
try {
const response = await fetch(
'http://myAPI/public/api/getPassengers',
{
method: 'POST',
headers: {
Authorization: `Bearer ${userToken}`,
Accept: 'application/json',
'Content-Type': 'application/json',
},
},
);
const responseJson = await response.json();
if (has(responseJson, 'error')) {
this.setState({ error: true });
Alert.alert('Error', 'Please check your credentials.');
} else {
passengersDataActionHandler(responseJson.success.data);
}
} catch (error) {
this.setState({ error: true });
Alert.alert(
'Error',
'There was an error with your request, please try again later.',
);
}
}
};
render() {
return <TabView style={styles.container} />;
}
}
HomeScreen.defaultProps = {
userToken: null,
};
HomeScreen.propTypes = {
navigation: PropTypes.shape({}).isRequired,
passengersDataActionHandler: PropTypes.func.isRequired,
userToken: PropTypes.oneOfType([PropTypes.string]),
};
export default compose(
connect(
store => ({
userToken: store.signinScreen.userToken,
passengersData: store.homeScreen.passengersData,
}),
dispatch => ({
passengersDataActionHandler: token => {
dispatch(passengersDataAction(token));
},
}),
),
)(HomeScreen);
With this implementation, the component renders many times so it breaks the application.
What could I be doing wrong?
First of all you don't need to store userToken in state since you are not modifying it locally and hence you don't need getDerivedStateFromProps
Secondly, you need to trigger API call in componentDidUpdate only on as prop change and not directly without a check otherwise, the setState inside the API success or error will cause the component to re-render calling componentDidUpdate again and thus calling the API again resulting in a infinite loop
Third, the check inside shouldComponentUpdate comparing props is not exactly correct since nestedObjects props will give a false negative result and also if you write a deep equality check for props, the component won't re-render if the state changes.
// imports
class HomeScreen extends Component {
static navigationOptions = {
header: null,
};
state = {
error: false,
};
componentDidMount() {
this.GetPassengersData();
}
componentDidUpdate(prevProps, prevState) {
if (prevProps.userToken !== this.props.userToken) {
this.GetPassengersData();
}
}
GetPassengersData = async () => {
const { passengersDataActionHandler, userToken } = this.props;
if (userToken && userToken !== null) {
try {
const response = await fetch(
'http://myAPI/public/api/getPassengers',
{
method: 'POST',
headers: {
Authorization: `Bearer ${userToken}`,
Accept: 'application/json',
'Content-Type': 'application/json',
},
},
);
const responseJson = await response.json();
if (has(responseJson, 'error')) {
this.setState({ error: true });
Alert.alert('Error', 'Please check your credentials.');
} else {
passengersDataActionHandler(responseJson.success.data);
}
} catch (error) {
this.setState({ error: true });
Alert.alert(
'Error',
'There was an error with your request, please try again later.',
);
}
}
};
render() {
return <TabView style={styles.container} />;
}
}
HomeScreen.defaultProps = {
userToken: null,
};
HomeScreen.propTypes = {
navigation: PropTypes.shape({}).isRequired,
passengersDataActionHandler: PropTypes.func.isRequired,
userToken: PropTypes.oneOfType([PropTypes.string]),
};
export default compose(
connect(
store => ({
userToken: store.signinScreen.userToken,
passengersData: store.homeScreen.passengersData,
}),
dispatch => ({
passengersDataActionHandler: token => {
dispatch(passengersDataAction(token));
},
}),
),
)(HomeScreen);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With