简体   繁体   中英

How to set state with React hooks from async fucntion return

I have a React module that makes a call to a function from an API in another JS module it imports. This function makes an async call to a flask route in my backend which returns a JSON object.

setSearchData is a useState.

In my React app, I setSearchData(getData(searchTerm)) with the expectation that the getData(searchTerm) function will asynchronously return something. When my promsie is resolved it should pipe jason data as such:

flask route -> searchAPI async func -> exported API func -> setState via hook

getsearch(search_term) -> flaskRoute(route, searchTerm) -> getSearchData(searchTerm) -> setSearchData( getSearchData(searchTerm) )

This doesn't work of course. The JSON data does get returned but it never updates the state. It seems as if the state gets updated with null and doesn't wait for the promise to get resolved.

How can I get an async function to play nice with React state which is itself async?

api_flask_routes.py

from flask import jsonify, request

@bp.route('/search/<search_term>', methods=['GET'])
def getsearch(search_term):
    search_data = [
        ['stuff'],
        ['stuff'],
        ['stuff'],
        ...
    ]
    return jsonify(search_data)

SearchDataAPI.js

async function regularRoute({ route, searchTerm = '', method = 'GET' }) {
    const routeWithSearchTerm = `${route}/${searchTerm}`;
    const endpoint = `${HOST_IP_ADDRESS}${searchTerm ? routeWithSearchTerm : route}`;
    const configs = {
        method,
        mode: 'cors',
        headers: { 'Content-Type': 'application/json' },
    };

    return fetch(endpoint, configs)
        .then(res => res.json())
        .then(data => data)
        .catch((err) =>  console.error(err));
}

function getSearchData(searchTerm) {
   return flaskRoute("/api/search/", searchTerm); // returns json to importing module
}

MySearch.js this is a React component

import searchDataAPI from '../searchAPI/SearchDataAPI';

//// DATA RETRIEVAL FROM BACKEND ////
const [searchData, setSearchData] = useState(null);
const getSearchData = searchDataAPI.searchFunctions.getSearchData;

function handleSubmitSearch(e) {
  e.preventDefault();
  if (searchTerm.trim().length > 0) {
      setSearchData(null); // clears out previous search data
      setSearchData(getSearchData(searchTerm)); // this doesn't work!
      // more stuff...
    }
}

you have to wait for your function resolve by using.then() like the following:

 getSearchData(searchTerm).then(result => {
    setSearchData(result)
});

if it still return null, then you have to change your getSearchData() to async, so it can also return the resolve result like:

async function getSearchData(searchTerm) {
   return await flaskRoute("/api/search/", searchTerm).then(res => {
    return res;
  });
}

if that also doesn't work, you can directly setState inside getSearchData() like:

function getSearchData(searchTerm) {
   flaskRoute("/api/search/", searchTerm).then(result => {
     setSearchData(result);
});
}

The answer is to use an asynchronous function in the file that has the React useState/setState function and any other function in between. Keep in mind that the useState hook is asynchronous itself.

async function regularRoute({ route, searchTerm = '', method = 'GET' }) {
    const routeWithSearchTerm = `${route}/${searchTerm}`;
    const endpoint = `${HOST_IP_ADDRESS}${routeWithSearchTerm}`;
    const configs = {
        method,
        mode: 'cors',
        headers: { 'Content-Type': 'application/json' },
    };

    return fetch(endpoint, configs)
        .then(res => res.json())
        .then(data => data)
        .catch((err) =>  console.error(err));
}

async function getSearchData(searchTerm) {
   const data = await flaskRoute('/api/search/', searchTerm);
   return data;
}

Then in my React file:

import React, { useState } from 'react';

const [data, setData] = useState('');

async function handleClick(e, searchTerm) {
    e.preventDefault();
    const newData = await getSearchData(searchTerm);
    setData(newData);
};

Done.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM