useState问题

时间:2020-04-19 04:50:03

标签: reactjs react-hooks

经过编辑以包含父类...

我在使用useState挂钩从功能组件更改状态时遇到问题。我在这里做错了什么?我为此加了星号。 locationOne和locationTwo运作良好。本质上,这是我正在制作的应用程序的一部分,该应用程序使用mapbox api计算两个坐标之间的距离。

import React, { useState, useEffect } from "react";
import { COORDS } from "./coords";

const CustomTrip = ({
  locationOne,
  locationTwo,
  onLocationOneChange,
  onLocationTwoChange
}) => {
  const [totalMiles, setTotalMiles] = useState(0);

  async function fetchDistance() {
    const res = await fetch(
      "https://api.mapbox.com/directions-matrix/v1/mapbox/driving/" +
        locationOne +
        ";" +
        locationTwo +
        "?sources=1&annotations=distance&access_token=****"
    );
    const mapBoxObject = await res.json();

    const meters = mapBoxObject.distances[0];
    const miles = parseInt(meters) * 0.00062137119;
    setTotalMiles(miles.toFixed(2));
    console.log(miles.toFixed(2));
  }

  useEffect(() => {
    fetchDistance();
  }, [locationOne, locationTwo]);

  return (
    <div>
      <center>
        <h1>Customize your trip</h1>
      </center>
      Select your starting point
      <select value={locationOne} onChange={onLocationOneChange}>
        {Object.entries(COORDS).map(([campus, longLatt]) => (
          <option key={campus} value={longLatt}>
            {campus}
          </option>
        ))}
      </select>
      Select your destination
      <select value={locationTwo} onChange={onLocationTwoChange}>
        {Object.entries(COORDS).map(([campus, longLatt]) => (
          <option key={campus} value={longLatt}>
            {campus}
          </option>
        ))}
      </select>
    </div>
  );
};

export default CustomTrip;

以下是父类组件的相关位:

class TippingPoint extends React.Component {
    constructor(props) {
      super(props);
      this.state = {
        totalMiles: 0,
        locationOne: '-97.4111604,35.4653761',
        locationTwo: '-73.778716,42.740913'       
      }



      this.onTotalMileChange.bind(this);
      this.onLocationOneChange.bind(this);
      this.onLocationTwoChange.bind(this);
    }  

    calculateTotals = () =>{ .... }



    onTotalMileChange = (event) => {
      this.setState({totalMiles: parseInt(event.target.value)},this.calculateTotals)    
    };

    onLocationOneChange = (event) => {
      this.setState({locationOne: event.target.value}, this.calculateTotals)
    }
    onLocationTwoChange = (event) => {
      this.setState({locationTwo: event.target.value}, this.calculateTotals)
    }

    render(){



                    <div>
                      <p>Trip Builder</p>

                          <CustomTrip totalMiles={this.state.totalMiles} locationOne={this.state.locationOne} 
                          locationTwo={this.state.locationTwo} onLocationOneChange={this.onLocationOneChange} 
                          onLocationTwoChange={this.onLocationTwoChange} onTotalMileChange={this.onTotalMileChange}/>

                    </div>


  export default TippingPoint;

3 个答案:

答案 0 :(得分:1)

听起来更像是您还需要传递回调CustomTrip才能将totalMiles传递回父组件。现在也无需将totalMiles暂时存储在状态中,可以直接在回调中传递它。

const CustomTrip = ({
  locationOne,
  locationTwo,
  onLocationOneChange,
  onLocationTwoChange,
  onTotalMilesComputed
}) => {
  async function fetchDistance() {
    const res = await fetch(
      "https://api.mapbox.com/directions-matrix/v1/mapbox/driving/" +
        locationOne +
        ";" +
        locationTwo +
        "?sources=1&annotations=distance&access_token=****"
    );
    const mapBoxObject = await res.json();

    const meters = mapBoxObject.distances[0];
    const miles = parseInt(meters) * 0.00062137119;

    onTotalMilesComputed(miles.toFixed(2)); // <-- passed callback
    console.log(miles.toFixed(2));
  }

  useEffect(() => {
    fetchDistance();
  }, [locationOne, locationTwo]);

...

父组件现在只需要一个处理程序即可。 (如果父级是功能组件,则使onTotalMilesComputed常量并省略this.

onTotalMilesComputed = totalMilage => {
  // do something with totalMilage, like set/update state
}

...

render() {
  ...
  return (
    ...
    <CustomTrip
      // ...all other passed props, locations, etc...
      onTotalMilesComputed={this.onTotalMilesComputed}
    />
    ...
  );
}

答案 1 :(得分:0)

不确定您面临的问题到底是什么。但是就useState而言,请尝试将其放在CustomTrip声明之外的import语句之后。

答案 2 :(得分:0)

不是答案,只是建议:

感觉不到此功能,因为它属于组件的 。它基本上是一个纯函数;接受一些参数并返回结果。而且,至少我希望,对于相同的参数,始终保持相同的结果

async function fetchDistance(locationOne, locationTwo) {
  const res = await fetch(
    "https://api.mapbox.com/directions-matrix/v1/mapbox/driving/" +
      locationOne +
      ";" +
      locationTwo +
      "?sources=1&annotations=distance&access_token=****"
  );
  const mapBoxObject = await res.json();

  const meters = mapBoxObject.distances[0];
  const miles = parseInt(meters) * 0.00062137119;

  console.log(miles.toFixed(2));
  return miles.toFixed(2);
}

在组件内部,您只需执行以下操作:

useEffect(() => {
  fetchDistance(locationOne, locationTwo).then(setTotalMiles);
}, [locationOne, locationTwo]);

这还可以帮助您将此逻辑移到父组件中,因为我认为它不属于您所显示的那个。 代码段中的Component仅仅是获得两个位置的受控输入。它没有状态,也没有逻辑,除了获得两个位置并将它们转发到父组件之外,什么也不做。

那么,为什么要逻辑计算给出给它的两个道具的距离,只是将结果“返回”给提供道具的组件呢?甚至不以任何方式使用该计算值。