'Warning: Can\'t perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application - react-native

im building a react native application ,still i have 2 screens
1.Enter mobile
2.Verify Otp
EnterUserInfo.js
class UserInfoInput extends Component {
constructor(props) {
super(props);
this.state = { formValid:true,
validMobileNumber:false,
.
.}}
componentWillReceiveProps(nextProps) {
if(nextProps.common.isFetching===false) {
this.props.navigation.navigate('VerifyOtpScreen')
.
.
} else {
this.setState({isLoading:true})
}}
onPressNext=()=> {
this.props.sendOtp(payload)}
render() {
return (<View/>)
}
}
}
function mapStateToProps(state) {
return {
common: state.common
}
}
function mapDispatchToProps(dispatch) {
return {
...bindActionCreators({ sendOtp }, dispatch)
}
}
export default connect(mapStateToProps,mapDispatchToProps)(UserInfoInput);
Here user enter the phone number ,and trigger an action sendOtp,response will be in the reducer and it will be available in the componentwillrecieveprops() lifecycle.
VerifyOtp.js
class VerifyOtp extends Component {
constructor(props) {
super(props);
this.state = { oneTimePIN: '' ,
.};
}
componentDidMount(){
this.setState({ phoneNumber:this.props.common.phone});
}
componentWillMount() {
setTimeout(() => {
this.setState({ isResendDisabled: false, opacity: 1 });
}, 30000);
}
componentWillReceiveProps(nextProps){
//do operation
}
onPressNext=()=>{
if(this.state.oneTimePIN=='') {
this.setState({showNotification:true})
}
else {
this.onSubmit()
}
}
onSubmit=()=>{
this.props.verifyOtp(payload)
}
onResendOtp=()=>{
this.props.sendOtp(payload,locationData)
this.setState({ isResendDisabled: true, opacity: 0.5 });
setTimeout(() => {
this.setState({ isResendDisabled: false, opacity: 1 });
}, 30000);
}
render() {
return (<View><Elements></View>)
}
}
function mapStateToProps(state) {
return {
common: state.common
}
}
function mapDispatchToProps(dispatch) {
return {
...bindActionCreators({ verifyOtp,sendOtp }, dispatch)
}
}
export default connect(mapStateToProps,mapDispatchToProps)(VerifyOtp);
VerifyOtp screen used to verify the otp.
The problem is,If i move back to enterUserinfo screen and move again to the verifyOtp screen im getting the warning message
'Warning: Can\'t perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application
What is the reason for the warning , and how tackle the issue?

This happens when you call an async function followed by setstate.
A simple work around would be like this:
constructor(props) {
this.state = {
...
this.isCancelled: false
}
}
componentWillMount() {
setTimeout(() => {
!this.state.isCancelled && this.setState({ isResendDisabled: false,
opacity: 1 });
}, 30000);
}
and in componentWillUnmount
componentWillUnmount() {
// setting it true to avoid setState waring since componentWillMount is async
this.state.isCancelled = true;
}

Related

How to check wifi status on change from Off to on

i want to use service in react-native using native modules ,if Wifi connectivity change from off to on just show toast that connection change
You can use react-native-netinfo plugin. Install this plugin and then add below code to your file :
import NetInfo from '#react-native-community/netinfo';
...
...
class App extends Component {
netInfoHandler;
constructor(props) {
super(props);
this.state = {
isConnected: true
}
}
componentDidMount = () => {
this.netInfoHandler = NetInfo.addEventListener(async (state) => {
if (this.state.isConnected !== state.isConnected) {
this.setState({ isConnected: state.isConnected });
// show toast here
}
});
}
componentWillUnmount = () => {
this.netInfoHandler();
}
render() {
return (
...
// your view
)
}
}
export default App

How can i refresh data with setInterval when Actions.pop()?

I'm trying to create live dashboard mobile app with react-native. I setInterval to fetch data every 5 sec. When i go to other actions i clearIntervar(cause if i don't clear it continues other pages) and it's ok but when i try to Action.pop() i cant setInterval again.
I tried to setInterval in componentWillUnmount() and Action.refresh(with same props) but every time; i get the same error.
Warning: Can't perform a React state update on an unmounted component.
This is a no-op, but it indicates a memory leak in your application.
To fix, cancel all subscriptions and asynchronous tasks in the
componentWillUnmount method.
This is the sample like my code:
export default class MyComponent extends Component {
constructor(props) {
super(props);
this.state = {
isRefresh: false
}
}
componentDidMount() {
this.getData()
}
async getData() {
//just a sample
const data = await fetch(url).then((response) => response.json());
this.setState({data: data});
if (this.state.isRefresh) {
const intervalId = setInterval(() => {
this.getData();
}, 5000);
this.setState({
intervalId: intervalId,
isRefresh: true
})
}
}
render() {
return (
<View>
<Text>{this.state.data}</Text>
<Button onPress={() => {
clearInterval(this.state.intervalId);
Action.otherPage();
}
} title={'Test Button'}/>
</View>
)
}
}
I have to setInterval and fetch data in the other pages too. So i need to clear when i go to other pages and need to setInterval when i come back with Actions.pop()
Don't store intervalId in state, instead you should make use of instance variable for your interval,
constructor(props) {
super(props);
this.state = {
isRefresh: false
}
this.intervalId = null; //instance variable
}
Then assign your interval to instance variable,
this.intervalId = setInterval(() => { this.getData();}, 5000);
Then use componentWillUnmount to clear interval,
componentWillUnmount(){
clearInterval(this.intervalId);
}
Please use this
componentDidMount() {
const { navigation } = this.props;
this.focusListener = navigation.addListener('didFocus', () => {
// The screen is focused
// Call any action you want when a user on this screen
});
}
componentWillUnmount() {
// Remove the event listener
this.focusListener.remove();
}

React Native : How to get device Screen Brightness and render it

I`m creating an React App to display device Info. I want to render Screen Brightness level, not in Console. How do I do it?
DeviceBrightness.getSystemBrightnessLevel().then(function(luminous) {
console.log(luminous)
})
I expected to render the screen brightness level, not to display in console
import DeviceBrightness from 'react-native-device-brightness';
export default class App extends Component{
constructor(props){
super(props);
this.state = {
isLoaded: false,
brightness: 0,
};
}
componentWillMount() {
DeviceBrightness.getSystemBrightnessLevel()
.then((luminous) =>{
this.setState({
brightness: luminous,
isLoaded: true,
});
});
}
render() {
return (
<View style={styles.container}>
<Text style={styles.instructions}>{this.state.brightness}</Text>
</View>
);
}
}
import DeviceBrightness from 'react-native-device-brightness';
export default class YourComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
isLoaded: false,
brightness: 0
};
}
componentDidMount() {
DeviceBrightness.getSystemBrightnessLevel()
.then(luminous => {
this.setState({
brightness: luminous,
isLoaded: true,
});
});
}
render() {
const { isLoaded, brightness } = this.state;
if (!isLoaded) {
return {/*loading view*/}
} else {
return (
<Text>{brightness}</Text>
);
}
}
}

react-native-camera barcode scanner freezes, because it scans too fast

I am trying to use the barcode scanner from react-native-camera. First, off it scans a QR-code and extracts a String, after that it navigates to the next Screen with react-navigation. In the second screen, it makes an API-call.
Now if I go back to the scanner screen, de QR-code will be scanned immediately. That's where I run into an error and the scanner freezes. I usually get this error:
Can't call setState (or forceUpdate) on an unmounted component
I think it's because my componentWillUnmount cleanup doesn't work properly or fast enough, but I already cancel the axios request.
requestCode = (code) => {
if (cancel != undefined) {
cancel();
}
axios.get(API_URI + code, {
cancelToken: new CancelToken(function executor(c) {
cancel = c;
})
}).then(response => {
console.log(response)
//checks if code was already called
this.checkUsed(response.data)
})
.catch(error => {
this.setState({ isValid: false })
});
}
componentWillUnmount() {
cancel();
}
Maybe I could mount the camera-scanner a little bit later so it doesn't scan this fast or is it maybe even an error with React Navigation?
You can use a flag to control.
class QR extends Component {
constructor(props) {
super(props)
this.state = {
scanable: true
}
this.cameraAttrs = {
ref: ref => {
this.camera = ref
},
style: styles.preview,
type: RNCamera.Constants.Type.back,
barCodeTypes: [RNCamera.Constants.BarCodeType.qr],
onBarCodeRead: ({ data }) => {
this.callback(data)
}
}
}
componentWillMount() {
this._mounted = true
}
componentWillUnmount() {
this._mounted = false
}
callback(text) {
if (!this.state.scanable) {
return
}
console.log(text)
this.setState({ scanable: false })
setTimeout(() => {
if (this._mounted) {
this.setState({ scanable: true })
}
}, 1000) // 1s cooldown
}
render() {
return (
<View style={styles.container}>
<RNCamera
{...this.cameraAttrs}
>
</RNCamera>
</View>
)
}
}

react native - DatePickerIOS with AsyncStorage

I have tried storing DatePickerIOS dates with redux.
Is there a way to use AsyncStorage? I have been trying with no luck so far. Are there any suggestions on how to use AsyncStorage with a simple DatePickerIOS component?
<DatePickerIOS
style={{ paddingTop: 110 }}
mode='date'
date={this.state.d}
onDateChange={(d) => this.onDateChange(d)}
/>
constructor(props) {
this.state = { date: newDate() };
}
onDateChange(d) {
this.setState({
d: d
});
You set the state for the d variable in onDateChange but you use the startDate variable in the DatePickerIOS.
Take a look at this, didn't tested in app but should work.
export class PickerIOS extends React.Component {
constructor() {
super();
this.state = {
pickedDate: null
}
}
componentWillMount() {
getData('date')
.then((date) => {
if (date != null)
this.setState({pickedDate: date})
else
this.setState({pickedDate: new Date()})
})
}
onDateChange(date) {
setData('date', date)
this.setState({pickedDate: date})
}
render() {
return (
<DatePickerIOS
mode='date'
date={this.state.pickedDate}
onDateChange={(date) => this.onDateChange(date)}
/>
);
}
}
and then, for code organisation, in another file:
setData(key, data) {
try {
await AsyncStorage.setItem(key, data);
} catch (error) {
// Error saving data
}
}
getData(key) {
try {
const value = await AsyncStorage.getItem(key);
if (value !== null){
return value
}
} catch (error) {
// Error retrieving data
}
}