0

I have a variable in state called isLoading. The idea is to display a loading message while the program is communicating the server, then display the data. However, at ling 24, I get an error:

TypeError: This.setState is not a function (in 'this.setState({ isloadin: false});

import React from "react";
import { StyleSheet, Text, View, AsyncStorage } from "react-native";

var text;

export default class App extends React.Component {
  constructor(props) {
    super(props);
    state = {
      isLoading: true
    };
  }

  componentDidMount = () => {
    AsyncStorage.getItem("accessToken").then(token => {
      postdata(
        "http://1.0.0.0:1337/loadTransactions",
        { UserID: 69 },
        function(result) {
          text = toString(result.Data[1].ID);
          text = result.Data[1].Label;
          console.log(result.Data[1].Label);
          this.setState({
            isLoading: false
          });
        }
      );
    });
  };
  render() {
    console.log(this.setState.isLoading);

    if (this.setState.isLoading) {
      console.log(this.setState.isLoading);
      return (
        <View style={styles.container}>
          <Text>Loading....</Text>
        </View>
      );
    } else {
      return (
        <View style={styles.container}>
          <Text>Hi, {text}</Text>
          <Text>Test</Text>
        </View>
      );
    }
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "#fff",
    alignItems: "center",
    justifyContent: "center"
  }
});
Caleb Bird
  • 65
  • 2
  • 7
  • 4
    Possible duplicate of [How to access the correct \`this\` inside a callback?](https://stackoverflow.com/questions/20279484/how-to-access-the-correct-this-inside-a-callback) – Quentin Jan 04 '19 at 07:54
  • Make sure how to use component state in react then use it, in your case remove the setState and log `this.state.isLoading` and use `this.setState({key:val})` when you need to set the state of the component – Vikas Singh Jan 04 '19 at 07:54
  • 3
    Unrelated, but `state = ...` should be `this.state = ...` in the constructor. – JJJ Jan 04 '19 at 07:55
  • @JJJ that's related I guess :D – Just code Jan 04 '19 at 07:58
  • May be you are having error because of this "`console.log(this.setState.isLoading);`". Remove that is you want the value of **isLoding** than console like this:"_`console.log(this.state.isLoading);`_" – Iva Jan 04 '19 at 08:15

2 Answers2

2

To maintain the context of a function as the same context where the function was lexically defined, you have to use an arrow function:

componentDidMount = () => {
  AsyncStorage.getItem("accessToken").then(token => {
    postdata(
      "http://204.48.23.161:1337/loadTransactions",
      { UserID: 69 },
      function(result) {
    // ^^^^^^^ use `result => ` here
        text = toString(result.Data[1].ID);
        text = result.Data[1].Label;
        console.log(result.Data[1].Label);
        this.setState({
          isLoading: false
        });
      }
    );
  });
};
nem035
  • 34,790
  • 6
  • 87
  • 99
  • ComponentDidMount() as an arrow function? That is some crazy new stuff. – Chris Ngo Jan 04 '19 at 07:57
  • 1
    That shouldn't matter for behavior. `= () => {}` is just a shorthand to define an instance method. Using this syntax makes the method be re-created for every instance where as using a prototype method maintains a single-copy for all instances but the behavior is unaffected either way. – nem035 Jan 04 '19 at 07:58
  • See for more info: https://stackoverflow.com/questions/48920135/es6-functions-arrow-functions-and-this-in-an-es6-class/48920356#48920356 – nem035 Jan 04 '19 at 08:01
  • The code works, but the console log still outputs "undefined" at console.log(this.setState.isLoading), and when I set isLoading to remain true, it doesn't render the loading message, any idea why? Thanks! – Caleb Bird Jan 04 '19 at 09:37
  • 1
    @CalebBird As you were told in the comments, it should be `this.state.isLoading`, not `this.setState.isLoading`. `setState` is only for setting the state, not retrieving it. – JJJ Jan 04 '19 at 09:38
  • I just tried that and it says "TypeError: undefined is not an object" – Caleb Bird Jan 04 '19 at 09:42
  • 1
    And that's because you have `state = ...` instead of `this.state = ...` in the constructor, which you were also told about earlier. – JJJ Jan 04 '19 at 09:45
0

this (ref to the instance of class) might not be available inside the context of AsyncStorage. Save this as another variable and use inside:

componentDidMount = () => {
  const self = this;
  AsyncStorage.getItem("accessToken").then(token => {
    postdata(
      "http://204.48.23.161:1337/loadTransactions",
      { UserID: 69 },
      function(result) {
        text = toString(result.Data[1].ID);
        text = result.Data[1].Label;
        console.log(result.Data[1].Label);
        self.setState({
          isLoading: false
        });
      }
    );
  });
};
Fawaz
  • 3,404
  • 3
  • 17
  • 22