Reputation: 1508
I have a react component which renders google map and also fetches data from an api. The google map dependency is loaded asynchronously when the component renders.
initial state:
state = {
isFetching: true
}
The component is wrapped in a HOC named withAsyncDependencies
:
import React from 'react';
import { isEmpty } from 'lodash';
// local dependencies
import { loadApi as loadMapApi } from '../../utils/googleMapLoader';
// global dependency store
const dependencies = {
google: null
};
/**
* @desc This HOC loads third-party JavaScript dependencies asynchronously.
* @example
* import { withAsyncDependencies } from 'ui/hoc/withAsyncDependencies';
*/
const withAsyncDependencies = ( Component ) => {
class WithAsyncDependencies extends React.Component {
constructor( props ) {
super( props );
// component state
this.state = {
isLoading: true
};
// load async dependencies
this.loadDependencies();
}
/**
* @desc Loading asyn
*/
loadDependencies() {
log.debug( 'WithAsyncDependencies.loadDependencies()' );
// load async dependencies which are missing from the global store
Promise.all( [
isEmpty( dependencies.google ) ? loadMapApi() : dependencies.google
] ).then( ( [ google ] ) => {
// add dependencies to global store
dependencies.google = google;
// update state
this.setState( {
isLoading: false
} );
} );
}
/**
* @desc Render component
*/
render() {
return (
<Component
{ ...this.props }
isLoadingAsyncDependencies={ this.state.isLoading }
asyncDependencies={ dependencies }
/>
);
}
}
// set display name
WithAsyncDependencies.displayName = 'WithAsyncDependencies';
// set default props
WithAsyncDependencies.defaultProps = {};
// return class
return WithAsyncDependencies;
};
export { withAsyncDependencies };
So now the HOC passes down props isLoadingAsyncDependencies
& asyncDependencies
Now I want to show a preloader while this.state.isFetching
is true and props.asyncDependencies.google
is not null.
I ran into an issue when I disconnected from an internet and my app threw errors in console as dependency google
hadn't loaded. But state isFetching
gets set to false
after the API response as both FE & BE are running on my localhost.
There are two routes google maps are required. To solve this issue one of my colleague used following condition on one page:
isReady = () => {
const asyncDependenciesLoaded = false === this.props.isLoadingAsyncDependencies;
const { google } = this.props.asyncDependencies;
if ( asyncDependenciesLoaded && google ) {
this.setState( { isReady: true } );
}
}
componentDidUpdate() {
if ( !this.state.isReady ) {
this.isReady();
}
}
render () {
const showPreLoader = !( !this.state.isFetching && this.state.isReady );
return (
<div className="providers-container">
<ProvidersPageView
isFetching = { showPreLoader }
/>
</div>
);
}
And my solution on another page is as follows:
render () {
const showPreLoader = this.state.isFetching || !this.state.isReady;
return (
<div className="providers-container">
<ProvidersPageView
isFetching = { showPreLoader }
/>
</div>
);
}
Both the conditions are working fine. I am wondering if both the conditions
!( !this.state.isFetching && this.state.isReady )
and this.state.isFetching || !this.state.isReady
are technically same?
which condition is more reliable and why?
Also does it matter if I switch the positions of variables in second condition like so:
!this.state.isReady || this.state.isFetching
?
Upvotes: 0
Views: 82
Reputation: 17382
Yes, !(!this.state.isFetching && this.state.isReady)
is logically equivalent to this.state.isFetching || !this.state.isReady
because of de Morgan's laws. What do you mean by "more reliable"? They are mathematically equivalent, thus none of them is "more reliable". But probably the second one is more readable, because you don't need parenthesis and only have a single negation.
Yes, mathematically speaking the order of operands in with &&
and ||
doesn't matter, because a || b == b || a
and a && b == b && a
.
But as most programming languages have short circuit evaluation of logical operations, you have to be careful, if your operands a
and b
have side-effects, which you rely on ...
Ie, a && b
won't evaluate b
if a
is already false, because the value of b
is irrelevant and the expression can never become true.
And a || b
won't evaluate b
if a
is already true, because the value of b
is again irrelevant and the expression will always be true.
So if a
and b
are not values but functions, and you rely on all of them to be executed, you may get a problem.
Imagine the following (pseudo)code
function a() {
this.prop = somevalue;
return false;
}
function b() {
this.otherprop = othervalue;
return true;
}
function c() {
if (a() && b())
dosomething();
}
In this code, b
will never be executed, thus this.otherprop
will probably never be set ...
Upvotes: 1