0

I'm trying to get a simple API call working, where the component calls the API as its mounting and sets the state to be rendered. But when I try to get the state to change an object in it, it says that the state is undefined.

TypeError: Cannot read property 'state' of undefined

class SpellGrid extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            value: '',
            spacing: '16',
            username: 'admin',
            password: 'notpassword',
            description: '',
            remember: false,
            spell: {
                name: '',
                school: '',
            },
        };

        this.handleChange = this.handleChange.bind(this);
        this.handleSubmit = this.handleSubmit.bind(this);
        this.mapApiToState = this.mapApiToState.bind(this);

    }

    mapApiToState() {
          // I've tried with all of the axios code in here.
    }


    componentDidMount() {

        axios
            .get("http://localhost:8000/api/spells/1")
            .then(function(response) {
                console.log('response', response);
                let fields = response.data[0].fields;
                // THIS IS THE LINE THAT IS ERRORING
                let spell = Object.assign({}, this.state.spell);

                spell.name =  fields.Name;
                spell.school =  fields.School;

                console.log('spell', spell);

                this.setState({spell});    

                console.log('state.spell', this.state.spell);
                //console.log('state', this.state);
            })
            .catch(function(error) {
                console.log(error);
            });

        console.log('state', this.state);
    }


    handleChange = name => event => {
        this.setState({
            [name]: event.target.value,
        });
    };


    onSubmit = (event) => {
        event.preventDefault();
        this.props.onSubmit(this.state.username, this.state.password)
    };


    handleSubmit(e) {
        console.log('Form state: ', this.state);
        e.preventDefault();
    }

    render() {
        const {classes, theme} = this.props;
        const { spacing } = this.state;

        return (
            <div>{this.state.spell.name}</div>
        );
    }
} export default withStyles(styles, { withTheme: true })(SpellGrid);
janhartmann
  • 13,440
  • 13
  • 78
  • 130
cclloyd
  • 5,118
  • 9
  • 39
  • 68
  • Possible duplicate of [Unable to access React instance (this) inside event handler](https://stackoverflow.com/questions/29577977/unable-to-access-react-instance-this-inside-event-handler) – Andrew Li May 01 '18 at 02:36
  • Also see: https://stackoverflow.com/questions/3127429/how-does-the-this-keyword-work – Andrew Li May 01 '18 at 02:37
  • @Li357 But I've tried putting all that code into `mapApiToState` and as you can see I binded it in the constructor already. – cclloyd May 01 '18 at 02:54
  • 1
    Even when using arrow functions in your axios calls? e.g. `.then( response => {` – Jayce444 May 01 '18 at 03:06
  • 1
    @Jayce444 That is definitely the problem. `this` is out of scope in OPs `.then` callback – Andrew May 01 '18 at 03:10
  • @cclloyd But check one level deeper. You promise then chain has a callback. It's a regular function expression which has a `this` pointing to the global object. Your bind won't help unless you rebind the callback or use arrow functions (see two duplicates posted) – Andrew Li May 01 '18 at 03:31
  • @Li357 so where should I put the api fetch then and where should I mutate the state? – cclloyd May 01 '18 at 05:42

1 Answers1

3

If you are using this, you will need to be carefull in which function scope you're in:

axios
  .get("http://localhost:8000/api/spells/1")
  .then(response => {
    // Since the `response` is now an arrow  function, we still
    // get access to the original `this`
    let fields = response.data[0].fields;
    let spell = Object.assign({}, this.state.spell);
    spell.name = fields.Name;
    spell.school = fields.School;
    this.setState({ 
      spell 
    });
  })
  .catch(error => {
    console.log(error);
  });
Andrew Li
  • 47,104
  • 10
  • 106
  • 132
janhartmann
  • 13,440
  • 13
  • 78
  • 130