I am trying to fetch some data from an API call. I am using getDerivedStateFromProps
, componentDidMount,
shouldComponentUpdateand
componentDidUpdate`.
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);
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments