0

I have a component fetching a API service that returns JSON. The service works, but the state on returns the json in the fetch after the second alert(this.state.questions); below.

My understanding of the execution stack of React is it shouldn't do that (I'm reasonable new to React). Or is it that state has a limited lifestyle time?

import React from 'react';
import { ConversationalForm } from 'conversational-form';

export default class MyForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      questions: []
    };
    this.submitCallback = this.submitCallback.bind(this);
  }

  componentDidMount() {
    fetch('http://localhost:3000/api/questions')
    .then((response) => response.json())
    .then((responseJson) => {
      this.setState({questions:JSON.stringify(responseJson)}, () => console.log(this.state.questions)); // Works fine, log has the json response
      alert(this.state.questions); // Returns expected JSON - runs after the next alert
    })
    alert(this.state.questions); // returns undefined - runs first

    this.cf = ConversationalForm.startTheConversation({
      options: {
        submitCallback: this.submitCallback,
        showProgressBar: true,
        preventAutoFocus: false,
      },
      tags: this.state.questions // returns undefined
    });
    this.elem.appendChild(this.cf.el);
  }
  
  submitCallback() {
    var formDataSerialized = this.cf.getFormData(true);
    console.log("Formdata, obj:", formDataSerialized);
    this.cf.addRobotChatResponse("Your are done. Grab a well deserved coffee.")
  }
  
  render() {
    return (
      <div>
        <div
          ref={ref => this.elem = ref}
        />
      </div>
    );
  }
}
Carl Bruiners
  • 516
  • 1
  • 7
  • 21

3 Answers3

0

i don't understand what's the problem, u expect the JSON to be at the second alert where there's undefined? which calls first ofc, because of the behavior of the async request, and it has nothing to do with react, it's a javascript thing.

if u need to run any code after there's a "questions" in the state, then u should use the componentDidUpdate and check if there's a "questions" in the state and then run the code.

if u would have used the React-Hooks it would be even easer :)

Y_Moshe
  • 424
  • 1
  • 5
  • 11
0

You can't depend on a state value in the same function in which it was set. There is no guarantee that the state (which updates async) will have finished updating before you use it at the bottom of componentDidMount. You should either:

1: Use the raw value and not the state value.

2: Use the state value after you are certain that it exists.

Also Note: You are not waiting for the promise to resolve before trying to use the state.

Grant Singleton
  • 1,611
  • 6
  • 17
0

fetch(url) returns Promise. In other words, it sends request to the url, it doesn't wait until receiving response and run next 'now' chunks - in this case, second alert command. So if you are going to process response, you should implement the processing code in the second 'then'.

.then(responseJson) {
  ...
  //process response
}

Or you can use async-await. 'Async-await' waits until coming response. If you don't understand, please feel free to ask me.

Jhonatan
  • 11
  • 4
  • So moving this.cf = ConversationalForm.startTheConversation({.... inside the second .the n? on the async-await, Ive looked @ examples but could see where I'd apply this... Thanks – Carl Bruiners Jan 28 '21 at 01:03