Reactjs useState的问题

Reactjs useState的问题,reactjs,react-hooks,Reactjs,React Hooks,已编辑以包含父类 我在使用useState钩子从功能组件更改状态时遇到问题。我做错了什么?我已经用星号标出了我的api密钥。位置一和位置二工作得很好。本质上,这是我正在制作的应用程序的一部分,它使用mapbox api计算两个坐标之间的距离 import React, { useState, useEffect } from "react"; import { COORDS } from "./coords"; const CustomTrip = ({ locationOne, lo

已编辑以包含父类

我在使用useState钩子从功能组件更改状态时遇到问题。我做错了什么?我已经用星号标出了我的api密钥。位置一和位置二工作得很好。本质上,这是我正在制作的应用程序的一部分,它使用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;
import React,{useState,useffect}来自“React”;
从“/COORDS”导入{COORDS};
常数CustomTrip=({
地点一,
地点二,
onLocationOneChange,
onLocationTwoChange
}) => {
常数[totalMiles,setTotalMiles]=useState(0);
异步函数fetchDistance(){
const res=等待取数(
"https://api.mapbox.com/directions-matrix/v1/mapbox/driving/" +
位置一+
";" +
地点二+
“?来源=1&注释=距离和访问\u标记=**”
);
const mapBoxObject=wait res.json();
常数米=mapBoxObject.distances[0];
常量英里数=帕塞因特(米)*0.00062137119;
设置总英里数(固定英里数(2));
控制台日志(英里到固定距离(2));
}
useffect(()=>{
fetchDistance();
},[位置一,位置二];
返回(
定制您的旅行
选择你的出发点
{Object.entries(COORDS.map)([campus,longLatt])=>(
{校园}
))}
选择你的目的地
{Object.entries(COORDS.map)([campus,longLatt])=>(
{校园}
))}
);
};
导出默认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;
类TippingPoint扩展了React.Component{
建造师(道具){
超级(道具);
此.state={
总英里数:0,
位置一:'-97.4111604,35.4653761',,
位置二:'-73.778716,42.740913'
}
this.onTotalMileChange.bind(this);
this.onlocationnechange.bind(this);
this.onLocationTwoChange.bind(this);
}  
calculateTotals=()=>{….}
onTotalMileChange=(事件)=>{
this.setState({totalMiles:parseInt(event.target.value)},this.calculateTotals)
};
onLocationOnChange=(事件)=>{
this.setState({locationOne:event.target.value},this.calculateTotals)
}
onLocationTwoChange=(事件)=>{
this.setState({locationTwo:event.target.value},this.calculateTotals)
}
render(){
行程生成器

导出默认提示点;
听起来更像是,为了将
totalMiles
传递回父组件,您还需要传递调用
CustomTrip
的回调。现在也不需要将
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]);

...

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

不是答案,只是一个建议:

这个函数感觉不属于组件内部。它基本上是一个纯函数;接受一些参数并返回一个结果。而且,至少我希望,对于相同的参数,总是相同的结果

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]);
这也可以帮助您将此逻辑移到父组件中,因为我认为它不属于您显示的那个组件。 代码段中的组件只是获取这两个位置的受控输入。除了获取这两个位置并将其转发给父组件之外,它没有任何状态和逻辑来执行任何操作


那么,它为什么要继续计算两个道具的距离,只是为了“返回”呢结果返回到提供道具的组件?甚至没有以任何方式使用该计算值。

您从
控制台.log
得到了什么输出?对于我选择的最后两个坐标,我得到了1357.39,那么到底是什么问题呢?您似乎没有使用
totalMiles
我在类compo中使用totalMiles是否也要附加它?状态可由组件使用或传递给子级(或回调中的父级).totalMiles应该用于什么?是不是其他地方的部分totalMiles没有被更新?处理程序会是什么样子?我现在一直在写这个。@Joshren在我的答案中添加了一个回调的实现。我实际上有一个totalMiles的更改处理程序,我使用它父组件中的其他计算,当我像您演示的那样使用它时,我得到“未处理的拒绝(TypeError):无法读取未定义的属性'value'”我的更改处理程序是:onTotalMileChange=(event)=>{this.setState({totalMiles:parseInt(event.target.value)},this.calculateTotals};@JoshWren嗯,你的
onTotalMileChange
接受一个事件对象,而不是计算的“总里程”值。
fetchDistance
也是一个异步函数,这意味着它隐式返回一个承诺,因此任何调用它的操作都可能会处理承诺拒绝。
fetchDistance
函数采用愉快路径,因此如果您正在处理的任何操作抛出错误,它将向上传播调用堆栈,直到捕获为止。
Fetch
返回一个承诺,但它不会在出错时拒绝,但是提取JSON数据可能会引发错误。如果fetch返回fetch失败,您应该首先检查
res.ok
useEffect(() => {
  fetchDistance(locationOne, locationTwo).then(setTotalMiles);
}, [locationOne, locationTwo]);