Undefined is not an object at this.state inside singleton - react-native

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: "" }

Related

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

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

React Native: Getting data from Firebase

I'm simply trying to retrieve data from the database in Firebase, and here's what I've got
var userList = [];
firebase.database()
.ref('/users/')
.once('value')
.then(snapshot => {
snapshot.forEach((doc) => {
userList.push(doc.val());
});
});
console.log(userList);
Even though I copy and pasted this code from a tutorial, the userList is empty outside of the snapshot. Can you tell me why that is?
The request to firebase is asynchronous so console.log(userList); is called before userList.push(doc.val()); gets called.
You should make userList a component state variable so that when you update it your component will re render.
Something like the following should work:
class UserListComponent extends Component {
constructor(props) {
super(props);
this.state = {
userList: [],
};
}
componentDidMount() {
this.getUsers();
}
getUsers() {
firebase
.database()
.ref('/users/')
.once('value')
.then((snapshot) => {
snapshot.forEach((doc) => {
this.setState({
userList: [...this.state.userList, doc.val()],
});
});
});
}
render() {
return (
<View>
{this.state.userList.map((item) => {
return (
<View>
<Text>{item.name}</Text>
</View>
);
})}
</View>
);
}
}

React native modal error evaluating _this5.state.error[key]

i'm still new to react native and i'm trying to make a modal with timer and i got an error say undefined is not an object (evaluating '_this5.state.error[key]') i tried to open the modal with setTimeout(), i think it has the problem with the state, anyone has an idea to fix it? Thanks
here is my code
class FormInput extends Component {
constructor(props) {
super(props);
const { fields, error } = props;
this.state = this.createState(fields, error);
this.state = {
visible: false
}
//bind functions
this.onChange = this.onChange.bind(this);
this.onSubmit = this.onSubmit.bind(this);
}
componentDidMount(){
this.timer = setTimeout(this.showModal, 5000); //auto reset after 60 seconds of inactivity
}
componentWillUnmount(){
clearTimeout(this.timer);
}
showModal() {
this.setState ({ visible: true})
}
closeModal() {
this.setState ({ visible: false})
}
createState(fields, error) {
const state = {};
fields.forEach((field) => {
let { key, type, value, mandatory } = field;
state[key] = { type: type, value: value, mandatory: mandatory };
})
state["error"] = error;
state["submitted"] = false;
return state;
}
render() {
return (
<View>
<AlertModal visible={this.showModal} close={this.closeModal}/>
</View>
);
Make showModal and closeModal an arrow function
showModal = () => {
this.setState ({ visible: true })
}
closeModal = () => {
this.setState ({ visible: false })
}
or bind them in constructor.
Also visible prop is a boolean and you are passing a function. Pass this.state.visible to fix the issue.
<AlertModal visible={this.state.visible} close={this.closeModal} />
--- UPDATED ---
So after checking out your updated code, I was able to figure out what was the issue. In constructor you are doing this
this.state = this.createState(fields, error);
this.state = {
visible: false
}
which overrides this.state. So I will suggest you to move visible: false into createState function and remove it from constructor.
declare showModal as a arrow function
showModal = () => {
this.setState ({ visible: true})
}
or bind the context for showModal
this.timer = setTimeout(this.showModal.bind(this), 5000)
or
this.timer = setTimeout(() => {this.showModal()}, 5000)
learn more about javascript context this

How can I compare two variable in onPress?

I am trying to create a changing pin screen and i was failed in comparing two variable that getting from the user (new pin and comfirm pin). The error show me that "this.state.newpin" is an undefined object.
class SettingScreen extends Component {
state = {
oldpin: '000000',
newpin: '',
secpin: ''
}
onPressButton(){
if( this.state.newpin == this.state.secpin){
ToastAndroid.show("Password Changed", ToastAndroid.SHORT);
this.setState({ oldpin : this.state.newpin})
}
else {
ToastAndroid.show("Password Unmatched", ToastAndroid.SHORT);
}
}
handleNewPin = (text) => {
this.setState({ newpin: text })
}
handleSecPin = (text) => {
this.setState({ secpin: text })
}
...
<TextInput onChangeText = {this.handleNewPin} />
<TextInput onChangeText = {this.handleSecPin} />
<TouchableOpacity onPress={this.onPressButton}>
<Text> Change Password </Text>
</TouchableOpacity>
I can get the output for "this.state.newpin" and "this.state.secpin" from user.
I just failed in the comparing statement ( OnPressButton()).
I am new in React-Native.
Sorry for any inconvenience.
you just need to bind your onPressButton()func. in the constructor with this. and move your state to constructor like this;
class SettingScreen extends Component {
constructor(props) {
super(props);
this.state = {
oldpin: '000000',
newpin: '',
secpin: ''
};
this.onPressButton = this.onPressButton.bind(this);
}
}

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'