Search code examples
javascriptreactjsauth0

How to fetch POST in a class component using @auth0/auth0-react


GET fetch will work, but when I attempt the POST fetch this is the error I'm seeing...

Unhandled Rejection (TypeError): Cannot read property 'props' of undefined

for this line... const { getAccessTokenSilently } = this.props.auth0;

import React, { Component } from 'react'
import { IP } from '../constants/IP'
import { withAuth0 } from '@auth0/auth0-react';

class AddATournament extends Component {

    componentDidMount() {
        this.myNewListOfAllTournamentsWithAuth()
    }

    state = {
        tournament_name: '',
        all_tournaments: [],
    }

    async myNewListOfAllTournamentsWithAuth() {
        const { getAccessTokenSilently } = this.props.auth0;
        const token = await getAccessTokenSilently({
          audience: `http://localhost:3000`,
          scope: 'read:tournaments',
        });

        fetch(`http://${IP}:3000/tournaments`, {
          headers: {
            Authorization: `Bearer ${token}`,
          },
        })
        .then(res => res.json())
        .then(data => this.setState({
            all_tournaments: data
        }))
    } 
    
    onChange = (e) => {
        this.setState({
            tournament_name: e.target.value
        })
    }

    async newHandleSubmitToAddATournamentWithAuth (event) {
        const { getAccessTokenSilently } = this.props.auth0;
        const token = await getAccessTokenSilently({
        audience: `http://localhost:3000`,
        scope: 'create:tournaments',
        });

        fetch(`http://${IP}:3000/tournaments`, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'Accepts': 'application/json',
                Authorization: `Bearer ${token}`
            },
            body: JSON.stringify({tournament_name: this.state.tournament_name,
            })
        })
    }

  render() {
   console.log("show me all tournaments", this.state.all_tournaments)

    return (
        <div className="App">
            <h2> Add A New Tournament
                {
                    <form onSubmit={this.newHandleSubmitToAddATournamentWithAuth}>
                        <br></br><label>
                        Tournament Name: 
                        <input 
                            onChange={this.onChange} 
                            type='text' tournament_name='tournament_name' 
                            value={this.state.tournament_name} />
                        </label>
                        <input type='submit' value='submit' />
                    </form>
                }
            </h2>
     )
  }
}

export default withAuth0(AddATournament);

Not sure that the componentDidMount is necessary for the GET. But think the issue with the POST may have something to do with rendering? I know I can't include the newHandleSubmitToAddATournamentWithAuth in the didMount because it takes in an event param. Please help!


Solution

  • I think the problem is you are not binding your functions to this. Methods defined in your Class do not have access to this unless you write them as arrow functions (like your onChange) or if you want to write them as functions, you need to bind them in constructor. Consider this solution:

    constructor() {
        super()
    
        this.state = {
          tournament_name: '',
          all_tournaments: [],
        }
    
        this.mymyNewListOfAllTournamentsWithAuth = this.mymyNewListOfAllTournamentsWithAuth.bind(this)
        this.newHandleSubmitToAddATournamentWithAuth = this.newHandleSubmitToAddATournamentWithAuth.bind(
          this
        )
      }
    

    If you want to avoid this in the constructor, you can modify your functions like this:

    const myNewListOfAllTournamentsWithAuth = async () => {...

    const newHandleSubmitToAddATournamentWithAuth = async (event) => {

    Arrow functions are automatically binded and have access to this