cjm2671
cjm2671

Reputation: 19476

How do I deal with promises in setState?

I have the following react code, that represents a text input.

 onChangeDestination(url, index) {
    this.setState(prevState => {
      const rules = [...prevState.rules];
      rules[index] = { ...rules[index], url};
      if (isURL(url+'')) {
        testURL(url).then(r=> {
          var url_status = r.data.response
          rules[index] = { ...rules[index], url_status};
        })
      } else {
         var url_status = "No URL"
         rules[index] = { ...rules[index], url_status};
      }
      return { rules };
    });
  };

In English:

If the URL passes isURL() validation, then use custom function testURL() to see what the HTTP status of that URL is (using axios).

In my template, there's a {props.url_status} for the relevant bit.

The issue is, even though it's logging to the console the desired behaviour, it doesn't seem to be updating the viewport reliably, which I think is linked to the promise.

What am I doing wrong?

Upvotes: 0

Views: 68

Answers (2)

Treycos
Treycos

Reputation: 7492

You could achieve it by converting your function to be asynchronous and calling your promise (if necessary) before your setState. This solution uses the easier to read async/await syntax and a ternary condition to choose the correct status value :

const url_status = isURL(url + '') ? (await testURL(url)).data.response : "No URL"

This line will execute your promise and wait for it only if isURL return true, if so it will return the response part and if not, it will send out "No URL".

Full code :

async onChangeDestination(url, index) {
    const url_status = isURL(url + '') ? (await testURL(url)).data.response : "No URL"
    this.setState(prevState => {
        const rules = [...prevState.rules];
        rules[index] = { 
            ...rules[index],
            url,
            url_status
        };
        return { rules };
    });
};

Upvotes: 1

gazdagergo
gazdagergo

Reputation: 6691

I recommend to use more components with some particular single task only. In this case: you might need a stateless Input component with an onChange and a value prop. Its parent could be some container where the onChange triggers some async request and has a state like url_status. As @Nit commented set the state in the promise then clause. This url_status will be a prop of some other component, so in case of the prop changes that component will re-render automatically... In most of the cases you do not need to use states at all.

Upvotes: 0

Related Questions