【问题标题】:Rerendering state in React after async call异步调用后在 React 中重新渲染状态
【发布时间】:2020-03-31 16:14:15
【问题描述】:

我试图在调用 Geolocation API 后将用户的当前城市加载到页面上。但是,调用 geolocation 函数的主要组件是在 Promise of location 返回之前将 state 设置为 undefined。

我的目标是使用用户的当前位置设置状态。但是,当我在 React 组件中调用 geolocate() 时, state.city 被设置为未定义,因为它不等待地理定位函数返回任何内容。

我的地理定位功能:

const geolocate = async () => {
    if (!navigator.geolocation) {
        alert('Geolocation is not supported by your browser. Please search for a location to look for weather');
    } else {
        getCoordinates().then((position) => {
            getCityByCoords(position)
            .then((response) => {
                return response;
            })
            .catch(err => console.log(err));
        })
        .catch(err => console.log(err));
    }   
}

const getCoordinates = () => {
    return new Promise((resolve, reject) => {
        navigator.geolocation.getCurrentPosition(
          position => {
            return resolve(position);
          },
          error => reject(error)
        )}
      );
};


// a call to my own API to make a request to Google's geocoding API
// response from this is coming back successfully
const getCityByCoords = (position) => {
    const { latitude, longitude } = position.coords;
    return axios.get('/city', {
        params: {
            lat: latitude,
            lng: longitude
        }
    })
}

我的组件中的函数调用:

 componentDidMount() {
    this.getLocation();
  }

  getLocation() {
    geolocate()
    .then(
      (response) => {
        this.setState({
            city: response,
            isLoaded: true
        })
    },
        (error) => {
            this.setState({
              isLoaded: true,
              error
            });
    })
    .then(() => {
      this.setState({ isLoaded: 'false' });
    })
  }

我认为所有这些异步调用都让我失望。

【问题讨论】:

    标签: javascript reactjs asynchronous promise async-await


    【解决方案1】:

    首先,您的geolocate 函数缺少返回语句,因此您可以在组件中的函数调用中获取定位结果。

    另外,不要嵌套 Promises,如果你可以返回它们。在下面的 sn-p 中,我重写了你的 geolocate 函数:

    const geolocate = async () => {
      if (!navigator.geolocation) {
        // better would be to throw an error here, so you can handle them in your component (or wherever else)
        alert(
          "Geolocation is not supported by your browser. Please search for a location to look for weather"
        );
      } else {
        // return was missing
        return getCoordinates()
          .then(position => getCityByCoords(position))
          .catch(err => console.log(err));
      }
    };
    

    在那之后,让我们解决你的问题:你没有在构造函数中初始化你的状态,所以在第一次渲染时,它不知道任何关于cityisLoaded 的信息。

    如果你将你的状态初始化放入你的构造函数,它应该打印你想要的城市,或者一个简单的“等待”段落:

    
    class Geo extends React.Component {
      constructor(props) {
        super(props);
    
        this.state = {
          city: "",
          isLoaded: false
        };
      }
    
      componentDidMount() {
        this.getLocation();
      }
    
      getLocation() {
        geolocate()
          .then(
            response => {
              this.setState({
                city: response,
                isLoaded: true
              });
            },
            error => {
              this.setState({
                isLoaded: true,
                error
              });
            }
          )
          .then(() => {
            this.setState({ isLoaded: "false" });
          });
      }
    
      render() {
        if (!this.state.isLoaded) {
          return <div>Waiting for Geolocation...</div>;
        }
        return <div>Geolocation: {this.state.city}</div>;
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2021-06-11
      • 2021-09-16
      • 2017-02-07
      • 2020-05-22
      • 2020-03-09
      • 2020-08-15
      • 1970-01-01
      • 2020-02-18
      • 2020-04-07
      相关资源
      最近更新 更多