Проблемы с использованием State - PullRequest
0 голосов
/ 19 апреля 2020

Отредактировано для включения родительского класса ...

У меня проблемы с изменением состояния из функционального компонента с помощью ловушки useState. Что я здесь не так делаю? Я обозначил для этого мой ключ API. locationOne и locationTwo работают отлично. По сути, это часть приложения, которое я делаю, которое вычисляет расстояние между двумя координатами с помощью API mapbox.

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 ]

1 голос
/ 19 апреля 2020

Похоже, вам также нужно передать обратный вызов для 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 const и пропустите this.)

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

...

render() {
  ...
  return (
    ...
    <CustomTrip
      // ...all other passed props, locations, etc...
      onTotalMilesComputed={this.onTotalMilesComputed}
    />
    ...
  );
}
0 голосов
/ 19 апреля 2020

не ответ, просто предположение:

Эта функция не ощущается как принадлежащая внутри Компонента. Это в основном чистая функция; принимает некоторые аргументы и возвращает результат. И, по крайней мере, я надеюсь, что всегда один и тот же результат для тех же аргументов

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]);

Это также может помочь вам переместить этот лог c в родительский компонент, так как я не думаю, что он принадлежит тому, который вы показываете. Компонент в вашем фрагменте - это просто контролируемый вход для получения двух местоположений. У него нет состояния и логики c, чтобы что-либо делать, кроме как получить два местоположения и переслать их в родительский компонент.

Так почему же он должен заключать в себе логику c, чтобы вычислить расстояние до двух заданных ему реквизитов, чтобы просто "вернуть" результат обратно компоненту, предоставившему реквизиты? Даже без использования этого вычисленного значения.

0 голосов
/ 19 апреля 2020

Не уверен, с чем именно вы столкнулись. Но что касается useState, попробуйте поместить его после оператора import вне объявления CustomTrip.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...