Undefined is not an object (evaluating 'this.setState') - react-native

I am getting value from shared preference, but when tried to store that value in this.state I am getting above error. I want to access business id globally so storing in this.state. Any help will be appreciated. Thank you.
this.state = {
businessId: ""
};
SharedPreferences.getItem("business_entity_id",function(value){
this.setState({businessId:value}).bind(this);
console.log("val",this.state.businessId);
});
console.log("businessId for shared Preference:", this.state.businessId);

You can use arrow function () => {} for function() {}, because when you use arrow function it will pass this into the function
this.state = {
businessId: ""
};
SharedPreferences.getItem("business_entity_id",(value) => {
this.setState({businessId:value}).bind(this);
console.log("val",this.state.businessId);
});
console.log("businessId for shared Preference:", this.state.businessId);

Is your code inside a React.Component? You cannot call it outside of React.Component.
This should work:
import React from "react";
import SharedPreferences from "react-native-shared-preferences";
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
businessId: "",
};
}
componentDidMount() {
SharedPreferences.getItem("key", (value) => {
this.setState({ businessId: value });
});
}
render() {
return (
<View></View>
);
}
}

Related

consuming Context on a Class Component

I'm new to context so may be a very easy error. I'm getting this error when triing to update the context:
[Unhandled promise rejection: TypeError: setUserInfo is not a function. (In 'setUserInfo(newUser)', 'setUserInfo' is undefined)]
Here is what I've done:
AppContext.js
import React, { Component } from 'react'
const AppContext = React.createContext();
class UserProvider extends Component {
// Context state
state = {
userInfo: {},
userChats: {},
userSettings: {},
}
// Method to update state
setUserInfo = (user) => {
this.setState((prevState) => ({ user }))
}
// Method to update state
setUserChats = (userChats) => {
this.setState((prevState) => ({ userChats }))
}
// Method to update state
setUserSettings = (settings) => {
this.setState((prevState) => ({ settings }))
}
render() {
const { children } = this.props
const { userInfo } = this.state
const { setUserInfo } = this
const { userChats } = this.state
const { setUserChats } = this
const { userSettings } = this.state
const { setUserSettings } = this
return (
<UserContext.Provider
value={{
userInfo,
setUserInfo,
userChats,
setUserChats,
userSettings,
setUserSettings,
}}
>
{children}
</UserContext.Provider>
)
}
}
export default AppContext
export { UserProvider }
Wrapping the App Component:
const defaultProviderValue = {userInfo: {}, userChats: {}, userSettings: {}}
<AppContext.Provider value = {defaultProviderValue}>
<Container>
<AppNavigator />
</Container>
</AppContext.Provider>
and then finally trying to update it on a class component:
import React, { Component} from 'react';
import AppContext from '../Context/AppContext.js'
class startScreen extends Component {
static contextType = AppContext
constructor(props) {
super(props);
this.state = {
};
}
async componentDidMount() {
const { userInfo, setUserInfo } = this.context
console.log("CONTEXT!!!!! : " + JSON.stringify(userInfo));
const newUser = { name: 'Joe', loggedIn: true };
setUserInfo(newUser); // ERROR fired: [Unhandled promise rejection: TypeError: setUserInfo is not a function. (In 'setUserInfo(newUser)', 'setUserInfo' is undefined)]
console.log("NEW CONTEXT!!!!! : " + JSON.stringify(userInfo));
}
render() {
return(null);
}
}
export default startScreen;
So how can I solve the error? It seems that can not find the method to update the value, but it's defined.
You are trying to use AppContext but you haven't set anything on itt apart from defaultValues. I guess you would want to use UserProvider and use AppContext within it
import React, { Component } from 'react'
const AppContext = React.createContext();
class UserProvider extends Component {
// Context state
state = {
userInfo: {},
userChats: {},
userSettings: {},
}
// Method to update state
setUserInfo = (user) => {
this.setState((prevState) => ({ user }))
}
// Method to update state
setUserChats = (userChats) => {
this.setState((prevState) => ({ userChats }))
}
// Method to update state
setUserSettings = (settings) => {
this.setState((prevState) => ({ settings }))
}
render() {
const { children } = this.props
const { userInfo } = this.state
const { setUserInfo } = this
const { userChats } = this.state
const { setUserChats } = this
const { userSettings } = this.state
const { setUserSettings } = this
return (
<AppContext.Provider
value={{
userInfo,
setUserInfo,
userChats,
setUserChats,
userSettings,
setUserSettings,
}}
>
{children}
</AppContext.Provider>
)
}
}
export default AppContext;
export { UserProvider };
<UserProvider>
<Container>
<AppNavigator />
</Container>
</UserProvider>
Post this change, you will be able to consume the context correctly

'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

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;
}

Undefined is not an object at this.state inside singleton

I'm fairly new at ReactNative. I have a singleton like this:
export default class Locker extends Component {
static data = Locker.data == null ? new Locker() : this.data;
constructor(props) {
super(props);
this.setState ({ username: "" });
AsyncStorage.getItem('username', (error, result) => {
if (result) { this.setState({ username: result }); }
});
this.getUsername = this.getUsername.bind(this);
this.setUsername = this.setUsername.bind(this);
}
getUsername = () => {
return this.state.username;
}
setUsername = (value) => {
AsyncStorage.setItem('username', value);
this.setState({ username: value });
}
}
And this is my main app:
export default class Home extends Component {
constructor(props) {
super(props);
this.showAlert = this.showAlert.bind(this);
}
showAlert() {
Alert.alert(
'This is an alert',
'Your saved username is ' + Locker.data.getUsername(),
[
{text: 'OK', onPress: console.log("Done")},
],
{cancelable: false},
);
}
render() {
return(
<View style={{ span: 1, backgroundColor: "white" }}>
<Button title="Press me" onPress={ () => this.showAlert() }/>
</View>
);
}
}
When I run the app, I see a button on the screen as expected. When I tap on the button, I get error undefined is not an object (evaluating '_this.state.username').
Why? I read somewhere that this may be because of .bind(this) and arrow function. That's why I add .bind(this) and arrow function everywhere. But still not solve the problem. This problem does not arise if I access state on the Home main class methods.
it is not a good idea to use setState() on the constructor, because react-native will render the component and its children (and this is not a proper thing to do in constructor because the component has not been rendered)
just initiate the state with this.state = {username: ""};
i think it is because of you did not define :
this.state = {
username: ""
}
in the constructor method ,replace it just after super(props)
Use this.state = {username: ""}instead of this.setState ({username: ""}) in constructor.
You don't need bind(this) if you use arrow functions
In your Locker class constructor just replace this code
from
constructor(props) {
super(props);
this.setState ({ username: "" });
AsyncStorage.getItem('username', (error, result) => {
if (result) { this.setState({ username: result }); }
});
this.getUsername = this.getUsername.bind(this);
this.setUsername = this.setUsername.bind(this);
}
to
constructor(props) {
super(props);
this.state={ username: "" };
AsyncStorage.getItem('username', (error, result) => {
if (result) { this.setState({ username: result }); }
});
this.getUsername = this.getUsername.bind(this);
this.setUsername = this.setUsername.bind(this);
}
Just need to replace this.state = { username: "" }

Setting state with a function in another file

Without attempting to update my state, the initial location in state is presented correctly. When I set state using a helper function, nothing is displayed in my app. What am I doing wrong? Additionally, logging props inside ShowLocation's render() shows that the coords{lat:xx,long:xx} are coming through correctly.
App.js
import * as helpers from './src/helpers';
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = globals.initial_state;
}
componentDidMount(){
this.setState({location:helpers.getLocation()});
}
render() {
return (
<View>
<ShowLocation coords={this.state.location} />
</View>
);
}
}
ShowLocation.js
class ShowLocation extends Component {
constructor(props){
super(props);
}
render(){
return(
<View>
<Text>{this.props.coords.lat}, {this.props.coords.long}</Text>
</View>
)
}
};
helpers.getLocation:
export function getLocation(){
coords = {};
navigator.geolocation.getCurrentPosition(
(position) => {
coords['lat'] = position.coords.latitude
coords['long'] = position.coords.longitude
},
(error) => this.setState({ navigatorError: error.message }),
{ enableHighAccuracy: true, timeout: 20000, maximumAge: 1000 },
);
return coords;
}
Did you tried:
componentDidMount(){
this.setState({ location: getLocation().bind(this) });
}
Or, same thing, but cleaner code:
constructor() {
// other stuff
this.getLocation = getLocation().bind(this)
}
componentDidMount(){
this.setState({ location: this.getLocation() });
}
Edit:
You must import { getLocation} from 'path/of/file'

Undefined props only in componentDidMount

In my code below you can see my component. How it is written will cause the app to crash with the error:
undefined is not an object (evaluation this.props.data.ID)
So in my componentDidMount that id variable is not receiving the props data.
However if i comment out that code in the componentDidMount the app will load fine and the props.data.ID will print out in View. Is there a reason why i can't access the props.data.ID in my componentDidMount?
Heres my code
// timeline.js
class TimelineScreen extends Component {
constructor(props) {
super(props);
this.state = {
posts: []
}
}
componentDidMount() {
const { id } = this.props.data.ID;
axios.post('/api/hometimeline', { id })
.then(res => {
this.setState({
posts: res.data
});
});
}
render() {
const { data } = this.props;
return (
<View style={s.container}>
{
data
?
<Text>{data.ID}</Text>
:
null
}
</View>
);
}
}
function mapStateToProps(state) {
const { data } = state.user;
return {
data
}
}
const connectedTimelineScreen = connect(mapStateToProps)(TimelineScreen);
export default connectedTimelineScreen;
The input of mapStateToProps is not react state, it is redux store. You shouldn't use this.setState in componentDidMount. Use redux actions and reducers to change redux store. Whenever redux store changes, it will invoke mapStateToProps and update your props
componentDidMount() {
console.log(this.props.data); // for test
const id = this.props.data.ID;
//OR
const {id} = this.props.data;
...
}