I want to test in all components whether the user has connection to the internet.
I could use NetInfo in each component, but since I am using redux, I thought it could be done easier with a middleware(?).
I have used
import { createStore, applyMiddleware } from 'redux';
const netInfo = store => next => action => {
const listener = (isConnected) => {
store.dispatch({
type: types.NET_INFO_CHANGED,
isConnected,
});
};
NetInfo.isConnected.addEventListener('change', listener);
NetInfo.isConnected.fetch().then(listener);
return next(action);
};
const store = createStore(AppReducer, applyMiddleware(netInfo));
where AppReducer is just combineReducers(navReducer, netInfoReducer, ...).
It does seem to work, but I am really worried if this performs well enough. It seems it is only run once, but I am never removing the listener or anything.
Is this how you normally would do if you want to populate all components with an isConnected variable?
I would create a Higher-Order Component for this:
import React, { Component } from 'react';
import { NetInfo } from 'react-native';
function withNetInfo(WrappedComponent) {
return class extends Component {
constructor(props) {
super(props);
this.state = {};
this.handleChange = this.handleChange.bind(this);
NetInfo.isConnected.fetch().then(this.handleChange);
}
componentDidMount() {
NetInfo.isConnected.addEventListener('change', this.handleChange);
}
componentWillUnmount() {
NetInfo.isConnected. removeEventListener('change', this.handleChange);
}
handleChange(isConnected) {
this.setState({ isConnected });
}
render() {
return <WrappedComponent isConnected={this.state.isConnected} {...this.props} />;
}
}
}
export default withNetInfo;
Then you can wrap whatever component you would like to render:
class MyComponent extends Component {
render() {
const { isConnected } = this.props;
return(
<View>
<Text>
{`Am I connected? ${isConnected}`}
</Text>
</View>
);
}
}
export default withNetInfo(MyComponent);
Bonus: if you want to keep the statics methods of your original component (if you have defined some) you should use the package hoist-non-react-statics to copy the non-react specific statics:
import React, { Component } from 'react';
import { NetInfo } from 'react-native';
import hoistStatics from 'hoist-non-react-statics';
function withNetInfo(WrappedComponent) {
class ExtendedComponent extends Component {
constructor(props) {
super(props);
this.state = {};
this.handleChange = this.handleChange.bind(this);
NetInfo.isConnected.fetch().then(this.handleChange)
}
componentDidMount() {
NetInfo.isConnected.addEventListener('change', this.handleChange);
}
componentWillUnmount() {
NetInfo.isConnected. removeEventListener('change', this.handleChange);
}
handleChange(isConnected) {
this.setState({ isConnected });
}
render() {
return <WrappedComponent isConnected={this.state.isConnected} {...this.props} />;
}
}
return hoistStatics(ExtendedComponent, WrappedComponent);
}
export default withNetInfo;
There shouldn't be a performance issue using middleware to keep "isConnected" in your redux store, but you would want to make sure the listener is only added once. I use https://github.com/michaelcontento/redux-middleware-oneshot to achieve that.
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