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

Javascript 未处理的拒绝(TypeError):ships.reduce不是一个函数,javascript,node.js,reactjs,Javascript,Node.js,Reactjs,我使用特定的API构建了一个船可视化工具。API返回一个json响应,我将其注入表中 问题:有时在白天,我注意到应用程序会停止工作,抛出以下实例: 未处理的拒绝(TypeError):ships.reduce不是一个函数 以下是错误的打印屏幕的完整性: 下面是我正在使用的代码: const ShipTracker = ({ ships, setActiveShip }) => { console.log("These are the ships: ", { ships });

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

问题:有时在白天,我注意到应用程序会停止工作,抛出以下实例:

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

以下是错误的打印屏幕的完整性:

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

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>
  );
};
const ShipTracker=({ships,setActiveShip})=>{
log(“这些是船:”,{ships});
返回(
#
MMSI
时间戳
纬度
经度
课程
速度
标题
导航器
依我所见
名称
呼号
{ships.map((ship,index)=>{
// 
{index}
{cells.map(cell=>(
{cell}
))}
);
})}
);
};
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>
    );
  }
}
class BoatMap扩展组件{
建造师(道具){
超级(道具);
此.state={
船舶:[],
过滤设备:[],
键入:“全部”,
船型:[],
activeShipTypes:[]
};
this.updateRequest=this.updateRequest.bind(this);
this.countDownInterval=null;
this.updateInterval=null;
this.map=null;
this.maps=null;
this.previousTimeStamp=null;
}
异步更新请求(){
常量url=”http://localhost:3001/hello";
const fetchingData=等待获取(url);
const ships=await fetchingData.json();
控制台日志(“获取的船舶”,船舶);
if(JSON.stringify(ships)!=“{}”){
if(this.previousTimeStamp==null){
this.previousTimeStamp=ships.reduce(函数(obj,ship){
obj[ship.AIS.NAME]=ship.AIS.TIMESTAMP;
返回obj;
}, {});
}
这是我的国家({
船舶:船舶,
过滤船
});
this.props.callbackFromParent(ships);
为了(让一艘船一艘船){
if(this.previousTimeStamp!==null){
if(this.previousTimeStamp[ship.AIS.NAME]==ship.AIS.TIMESTAMP){
this.previousTimeStamp[ship.AIS.NAME]=ship.AIS.TIMESTAMP;
log(“相同的时间戳:”,ship.AIS.NAME,ship.AIS.timestamp);
继续;
}否则{
this.previousTimeStamp[ship.AIS.NAME]=ship.AIS.TIMESTAMP;
}
}
让我们装运={
//船舶数据。。。
};
常量请求选项={
方法:“张贴”,
标题:{“内容类型”:“应用程序/json”},
正文:JSON.stringify(_ship)
};
待命(
"http://localhost:3001/users/vessles/map/latlng",
请求选项
);
//log('Post',Date());
}
}
}
render(){
const noHoverOnShip=this.state.hoverOnActiveShip==null;
返回(
{
this.map=map;
this.maps=maps;
//我们需要此设置状态来强制第一次mapcontrol渲染
this.setState({mapControlShouldRender:true,mapLoaded:true});
}}
>
{this.state.mapload&&(
)}
{Array.isArray(this.state.filteredShips)(
this.state.filteredShips.map(ship=>(
))
) : (
)}
);
}
}
导出默认类GoogleMap扩展React.Component{
状态={
船舶:[],
activeShipTypes:[],
活动公司:[],
activeShip:null,
shipFromDatabase:[]
};
setActiveShip=(名称、纬度、经度)=>{
这是我的国家({
活动船舶:{
名称
纬度,
经度
}
});
};
setShipDatabase=ships=>{
this.setState({shipFromDatabase:ships});
};
//将数据从子级传递到父级
callbackFromParent=发货=>{
这个.setState({ships});
};
render(){
返回(
{/*这是谷歌地图跟踪页面*/}

{
   ships?.map((ship, index) => 
   ...

   // or

  ships && ships.length > 0 && ships.map((ship, index) => 
  ....
}
{JSON.stringify(this.state.activeShip,null,2)} ); } }
到目前为止我所做的:

1) 我也来帮我解决这个问题,但运气不好

2) 我也咨询了他们,但他们都没有帮助我找出问题所在

3) 我深入研究了这个问题,发现了很多问题

4) 我读书。然而,这两种方法都没有帮助我解决这个问题

5) 我也发现非常有用,但仍然没有解决方案


Thanls为解决这个问题指明了正确的方向。

这可能是因为
在调用reduce时,ships
不是数组,可能是null

如果传递的父组件上的ships是state,那么它最初可能为null,然后获得更新,那么第一次呈现组件时,它的调用reduce是否为null

如果您使用的JavaScript版本支持空传播,则可以使用

ships?.reduce
以便在第一次呈现时,如果它为null,它不会尝试调用null上的reduce函数,但是当它呈现时,一切都应该很好,这是一种非常常见的模式

如果您的JavaScript版本不支持空传播,则可以使用


ships&&ships.length>0&&ships.reduce(…

所以你也应该改变


{ships.map((ship,index)=>{/这无法解决为什么
ships
道具不总是数组的问题,但它将帮助您保护代码免受此未处理异常的影响


{Array.isArray(ships)和&ships.map((ship,index)=>{
常数
<tbody>
   {Array.isArray(ships) && ships.map((ship, index) => {
      const {
        MMSI,
        // rest of your code here