0
import React, {Component} from 'react';
import './randomChar.css';
import GotService from '../../services/gotService';

export default class RandomChar extends Component {
    constructor(props){
        super(props);
        this.state = {
            name: '',
            gender: '',
            born: '',
            died: '',
            culture: ''
        }
        
    }
    getData(){
        const got = new GotService();
        const random = Math.round(Math.random()*2138);
            got.getCharacter(random)
            .then((res) => {
              console.log(res.name)
              this.setState({
                name: res.name
              })
            })
    }
    render() {
        return ( 
            <div className="random-block rounded">
                <button onClick={this.getData}>Click</button>
                <h4>Random Character: {this.state.name}</h4>
            </div>
        );
    }
}

File GotService.js

export default class GotService {
    constructor(){
        this._apiBase = 'https://www.anapioficeandfire.com/api'
    }
        async serverRun (url) {
        const res = await fetch(`${this._apiBase}${url}`);
    
        if (!res.ok) {
           throw new Error(`${res.status}`)
        }
        
        return await res.json();
    }
   
    getCharacter(id) {
        return this.serverRun(`/characters/${id}`)
    }
    
}

Why when I click on the button I get a response in the console:

Rohanne

Uncaught (in promise) TypeError: Cannot read properties of undefined

Why does the console output Rohanne, and the value of Rohanne is not written to state, but is displayed as undefined?

thank for helping

VLAZ
  • 26,331
  • 9
  • 49
  • 67
  • the context of getData is wrong. You could try `` – user3252327 Sep 26 '22 at 11:58
  • Because `this` isn't being set correctly when you call `getData`. See the linked question's answers and [the React documentation](https://reactjs.org/docs/faq-functions.html#how-do-i-bind-a-function-to-a-component-instance). – T.J. Crowder Sep 26 '22 at 11:58
  • 1
    @user3252327 - I prefer to do it once, in the constructor (`this.getData = this.getData.bind(this);`), so the callback is stable across renders. Helps if child components are memoized. – T.J. Crowder Sep 26 '22 at 12:00
  • or for a lighter syntax, we could define getData as an arrow function `private getData = () => {/* implementation */}` – user3252327 Sep 26 '22 at 12:02
  • thanks everyone, i forgot about bind – Евгений Sep 26 '22 at 12:24

0 Answers0