未处理的拒绝(TypeError):ships.reduce不是函数 [英] Unhandled Rejection (TypeError): ships.reduce is not a function

查看:49
本文介绍了未处理的拒绝(TypeError):ships.reduce不是函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用特定的API构建了船用可视化工具.该API返回一个json响应,并将其注入表中.

I built a boat visualizer using specific API. The API returns a json response that I injecting it in a table.

问题:有时在一天中,我注意到该应用程序将停止运行并抛出以下实例:

The problem: Sometimes during the day I noticed that the application would stop working throwing an instance of:

未处理的拒绝(TypeError):ships.reduce不是函数

为了完整起见,错误的打印屏幕如下:

Below for completeness the print screen of the error:

在我正在使用的代码下面:

Below the code I am using:

const ShipTracker = ({ ships, setActiveShip }) => {
  console.log("These are the ships: ", { ships });

  return (
    <div className="ship-tracker">
      <Table className="flags-table" responsive hover>
        <thead>
          <tr>
            <th>#</th>
            <th>MMSI</th>
            <th>TIMESTAMP</th>
            <th>LATITUDE</th>
            <th>LONGITUDE</th>
            <th>COURSE</th>
            <th>SPEED</th>
            <th>HEADING</th>
            <th>NAVSTAT</th>
            <th>IMO</th>
            <th>NAME</th>
            <th>CALLSIGN</th>
          </tr>
        </thead>
        <tbody>
          {ships.map((ship, index) => {
            // <-- Error Here
            const {
              MMSI,
              TIMESTAMP,
              LATITUDE,
              LONGITUDE,
              COURSE,
              SPEED,
              HEADING,
              NAVSTAT,
              IMO,
              NAME,
              CALLSIGN
            } = ship.AIS;

            const cells = [
              MMSI,
              TIMESTAMP,
              LATITUDE,
              LONGITUDE,
              COURSE,
              SPEED,
              HEADING,
              NAVSTAT,
              IMO,
              NAME,
              CALLSIGN
            ];

            return (
              <tr
                onClick={() =>
                  setActiveShip(
                    ship.AIS.NAME,
                    ship.AIS.LATITUDE,
                    ship.AIS.LONGITUDE
                  )
                }
                key={index}
              >
                <th scope="row">{index}</th>
                {cells.map(cell => (
                  <td key={ship.AIS.MMSI}>{cell}</td>
                ))}
              </tr>
            );
          })}
        </tbody>
      </Table>
    </div>
  );
};

Googlemap.js

class BoatMap extends Component {
  constructor(props) {
    super(props);
    this.state = {
      ships: [],
      filteredShips: [],
      type: "All",
      shipTypes: [],
      activeShipTypes: []
    };
    this.updateRequest = this.updateRequest.bind(this);
    this.countDownInterval = null;
    this.updateInterval = null;
    this.map = null;
    this.maps = null;
    this.previousTimeStamp = null;
  }

  async updateRequest() {
    const url = "http://localhost:3001/hello";
    const fetchingData = await fetch(url);
    const ships = await fetchingData.json();
    console.log("fetched ships", ships);

    if (JSON.stringify(ships) !== "{}") {
      if (this.previousTimeStamp === null) {
        this.previousTimeStamp = ships.reduce(function(obj, ship) {
          obj[ship.AIS.NAME] = ship.AIS.TIMESTAMP;
          return obj;
        }, {});
      }

      this.setState({
        ships: ships,
        filteredShips: ships
      });

      this.props.callbackFromParent(ships);

      for (let ship of ships) {
        if (this.previousTimeStamp !== null) {
          if (this.previousTimeStamp[ship.AIS.NAME] === ship.AIS.TIMESTAMP) {
            this.previousTimeStamp[ship.AIS.NAME] = ship.AIS.TIMESTAMP;
            console.log("Same timestamp: ", ship.AIS.NAME, ship.AIS.TIMESTAMP);
            continue;
          } else {
            this.previousTimeStamp[ship.AIS.NAME] = ship.AIS.TIMESTAMP;
          }
        }

        let _ship = {
          // ship data ...
        };
        const requestOptions = {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify(_ship)
        };
        await fetch(
          "http://localhost:3001/users/vessles/map/latlng",
          requestOptions
        );
        // console.log('Post', Date());
      }
    }
  }

  render() {
    const noHoverOnShip = this.state.hoverOnActiveShip === null;
    return (
      <div className="google-map">
        <GoogleMapReact
          bootstrapURLKeys={{ key: "key" }}
          center={{
            lat: this.props.activeShip ? this.props.activeShip.latitude : 37.99,
            lng: this.props.activeShip
              ? this.props.activeShip.longitude
              : -97.31
          }}
          zoom={5.5}
          onGoogleApiLoaded={({ map, maps }) => {
            this.map = map;
            this.maps = maps;
            // we need this setState to force the first mapcontrol render
            this.setState({ mapControlShouldRender: true, mapLoaded: true });
          }}
        >
          {this.state.mapLoaded && (
            <div>
              <Polyline
                map={this.map}
                maps={this.maps}
                markers={this.state.trajectoryData}
                lineColor={this.state.trajectoryColor}
              />
            </div>
          )}

          {Array.isArray(this.state.filteredShips) ? (
            this.state.filteredShips.map(ship => (
              <Ship
                ship={ship}
                key={ship.AIS.MMSI}
                lat={ship.AIS.LATITUDE}
                lng={ship.AIS.LONGITUDE}
                logoMap={this.state.logoMap}
                logoClick={this.handleMarkerClick}
                logoHoverOn={this.handleMarkerHoverOnShip}
                logoHoverOff={this.handleMarkerHoverOffInfoWin}
              />
            ))
          ) : (
            <div />
          )}
        </GoogleMapReact>
      </div>
    );
  }
}

export default class GoogleMap extends React.Component {
  state = {
    ships: [],
    activeShipTypes: [],
    activeCompanies: [],
    activeShip: null,
    shipFromDatabase: []
  };

  setActiveShip = (name, latitude, longitude) => {
    this.setState({
      activeShip: {
        name,
        latitude,
        longitude
      }
    });
  };

  setShipDatabase = ships => {
    this.setState({ shipFromDatabase: ships });
  };

  // passing data from children to parent
  callbackFromParent = ships => {
    this.setState({ ships });
  };

  render() {
    return (
      <MapContainer>
        {/* This is the Google Map Tracking Page */}
        <pre>{JSON.stringify(this.state.activeShip, null, 2)}</pre>
        <BoatMap
          setActiveShip={this.setActiveShip}
          activeShip={this.state.activeShip}
          handleDropdownChange={this.handleDropdownChange}
          callbackFromParent={this.callbackFromParent}
          shipFromDatabase={this.state.shipFromDatabase}
          renderMyDropDown={this.state.renderMyDropDown}
          // activeWindow={this.setActiveWindow}
        />
        <ShipTracker
          ships={this.state.ships}
          setActiveShip={this.setActiveShip}
          onMarkerClick={this.handleMarkerClick}
        />
      </MapContainer>
    );
  }
}

我到目前为止所做的事情:

1)我也遇到了此来源来帮助我解决问题,但是没有运气.

1) I also came across this source to help me solve the problem but no luck.

2)我还查阅了其他来源,还有这一个,但是它们都没有帮助我找出可能是什么问题.

2) Also I consulted this other source, and also this one but both of them did not help me to figure out what the problem might be.

3)我对问题进行了深入研究,发现

3) I dug more into the problem and found this source too.

4)我也阅读了这一个一个>.但是,这些都没有帮助我解决问题.

4) I read this one too. However, neither of these has helped me fix the problem.

5)我还发现了这个来源非常有用,但仍然没有解决方案.

5) I also found this source very useful but still no solution.

感谢您指出解决此问题的正确方向.

Thanls for pointing to the right direction for solving this problem.

推荐答案

一种解决方法是,如果中的 fetch 请求出错,则默认为空数组updateRequest :

One way you could go about this is to default to an empty array if something goes wrong with your fetch request inside updateRequest:

async updateRequest() {
  const url = "http://localhost:3001/hello";
  const defaultValue = [];
  const ships = await fetchShips(url, defaultValue);

  // safe to use `Array` methods on an empty `array`
  if (this.previousTimeStamp === null) {
    this.previousTimestamp = ships.reduce(...);
  }
}

function fetchShips(url, defaultValue) {
  return fetch(url)
    .then(response => {
      if (!response.ok) {
        throw Error(response.statusText);
      }
      return response.json();
    })
    .then(data => {
      if (Array.isArray(data)) {
        return data;
      }
      // return the default value (empty array)
      // so that your application doesn't crash 
      return defaultValue;
    })
    .catch(error => {
      console.error(error.message);

      // catch other errors and return the default
      // value (empty array), so that your application doesn't crash
      return defaultValue;
    });
}

但是,您应该适当地处理错误,并显示一条消息,指出出现问题是为了获得更好的用户体验,而不是根本不显示任何内容.

However, you should handle errors appropriately and show a message that says something went wrong for a better user experience rather than not showing anything at all.

async updateRequest() {
  const url = "http://localhost:3001/hello";
  const defaultValue = [];
  const ships = await fetchShips(url, defaultValue).catch(e => e);

  if (ships instanceof Error) {
    // handle errors appropriately
    return;
  }
  // otherwise continue, with an empty array still a
  // possibility, but won't break the app
  if (this.previousTimeStamp === null) {
    this.previousTimestamp = ships.reduce(...);
  }
}

function fetchShips(url, defaultValue) {
  return fetch(url)
    .then(response => {
      if (!response.ok) {
        throw Error(response.statusText);
      }
      return response.json();
    })
    .then(data => {
      if (Array.isArray(data)) {
        return data;
      }
      // return the default value (empty array)
      // so that your application doesn't crash 
      return defaultValue;
    });
}

这篇关于未处理的拒绝(TypeError):ships.reduce不是函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆