未处理的拒绝(TypeError):planets.filter不是函数

时间:2019-03-25 14:05:32

标签: javascript reactjs redux

我正在使用redux来管理状态。

在我的app.js中,有一个promise函数。

用于获取行星的名称,直径和自转周期

在我将promise函数更改为

之后,这里出现了问题
 this.props.onRequestPlanets():

删除了builder()并设置了行星,isPending到this.props

我的网站显示错误

未处理的拒绝(TypeError):planets.filter不是函数

这是图片:

enter image description here

我该怎么办?

app.js中的Promise函数:

   componentDidMount() {
           const urls = [
        'https://swapi.co/api/planets/',
        'https://swapi.co/api/planets/?page=2', 
        'https://swapi.co/api/planets/?page=3',
        'https://swapi.co/api/planets/?page=4',
        'https://swapi.co/api/planets/?page=5',
        'https://swapi.co/api/planets/?page=6',
        'https://swapi.co/api/planets/?page=7'
    ]

    Promise.all(urls.map(async url => {
        const response = await fetch(url);
        const morePlanets = await response.json();
        var combinedArrayOfPlanets = this.state.planets;
        combinedArrayOfPlanets.push(morePlanets.results);

        var sortedArrayOfPlanets = combinedArrayOfPlanets
            .flat()
            .sort((a, b) => a.name.localeCompare(b.name));

        this.setState({planets: sortedArrayOfPlanets})
    }))
    .catch(error => 
        console.log('Error during fetching of planets:', error)
    );
}

我的app.js:

  import React,{Component} from 'react';
  import {connect} from 'react-redux';
  import CardList from '../Components/CardList';
  import SearchBox from '../Components/SearchBox';
  import Scroll from '../Components/Scroll';
  import './App.css';
  import {setSearchField,requestPlanets} from '../action'

  const mapStateToProps=state=>{
      return{
         searchField:state.searchPlanets.searchField,
         planets:state.requestPlanets.planets,
         isPending:state.requestPlanets.isPending,
         error:state.requestPlanets.error
       }
     }

 const mapDispatchToProps=(dispatch)=>{
 return {
    onSearchChange:(event)=>dispatch(setSearchField(event.target.value)),
    onRequestPlanets:()=>dispatch(requestPlanets())
 }
  }




class App extends Component{
 componentDidMount() {
     this.props.onRequestPlanets();
}

render()
    const {searchField,onSearchChange,planets,isPending}=this.props;
     if (isPending) {
        return <div className='tc'><h1>Loading</h1></div>;
     }
    const filteredPlanets = planets.filter(planet=>{
        return planet.name.toLowerCase().includes(
            searchField.toLowerCase())
            ||
            planet.diameter.toLowerCase().includes(
                searchField.toLowerCase())
            ||
            planet.rotation_period.toLowerCase().includes(
                searchField.toLowerCase())
    })
    return (
    <div className='tc'>
        <h1 className='f2'>StarWarPlanet</h1>
        <SearchBox searchChange={onSearchChange}/>
        <Scroll>
            <CardList planets = {filteredPlanets}/>
        </Scroll>
    </div>
    );
    }
 }

 export default connect(mapStateToProps,mapDispatchToProps)(App);

我的action.js:

 import{
CHANGE_SEARCH_FIELD,
REQUEST_PLANETS_PENDING,
REQUEST_PLANETS_SUCCESS,
REQUEST_PLANETS_FAILED 
  }from './constants.js'

 export const setSearchField=(text)=>({
type:CHANGE_SEARCH_FIELD,
payload:text
 })

  export const requestPlanets = ()=>(dispatch)=>{
dispatch({type:REQUEST_PLANETS_PENDING})
fetch('https://swapi.co/api/planets/')
fetch('https://swapi.co/api/planets/?page=2') 
fetch('https://swapi.co/api/planets/?page=3')
fetch('https://swapi.co/api/planets/?page=4')
fetch('https://swapi.co/api/planets/?page=5')
fetch('https://swapi.co/api/planets/?page=6')
fetch('https://swapi.co/api/planets/?page=7')
    .then(response =>response.json())
    .then(data =>dispatch({type:REQUEST_PLANETS_SUCCESS,payload:data}))
    .then(error =>dispatch({type:REQUEST_PLANETS_FAILED,payload:error}))
 }

我的reducers.js:

  import{
CHANGE_SEARCH_FIELD,
REQUEST_PLANETS_PENDING,
REQUEST_PLANETS_SUCCESS,
REQUEST_PLANETS_FAILED 
  }from './constants.js'

   const initialStateSearch={
     searchField:''
  }

  export const searchPlanets=(state=initialStateSearch,action={})=>{
    switch(action.type){
      case CHANGE_SEARCH_FIELD:
        return Object.assign({},state,{searchField:action.payload})
     default:
        return state;
    }
 }

const initialStatePlanets={
    isPending:false,
     planets:[],
     error:''
}

export const requestPlanets = (state=initialStatePlanets,action={})=>{
    switch(action.type){
        case REQUEST_PLANETS_PENDING:
          return Object.assign({},state,{isPending:true})
         case REQUEST_PLANETS_SUCCESS:
      return Object.assign({},state,{planets:action.payload,isPending:false})
    case REQUEST_PLANETS_FAILED:
      return Object.assign({},state,{error:action.payload,isPending:false})
    default:
      return state;
   }
 }

1 个答案:

答案 0 :(得分:0)

fetch期望将对象作为第二个参数。在执行操作时会出现错误:

fetch('https://swapi.co/api/planets/',
        'https://swapi.co/api/planets/?page=2', 
        'https://swapi.co/api/planets/?page=3',
        'https://swapi.co/api/planets/?page=4',
        'https://swapi.co/api/planets/?page=5',
        'https://swapi.co/api/planets/?page=6',
        'https://swapi.co/api/planets/?page=7')

您要添加字符串作为第二,第三...参数,这是错误的。

另外,由于您现在将请求数据保存在商店中并通过mapStateToProps接收,因此您应该在渲染中进行更改:

const {planets} = this.state;

收件人:

const {planets} = this.props;

此外,在执行操作时要小心:

var combinedArrayOfPlanets = this.state.planets;

状态应该是不可变的,您不是在这里创建新对象,而只是在combinedArrayOfPlanets中添加对此this.state.planets的引用。因此,当您稍后更改combinedArrayOfPlanets时,您实际上是在更改状态。不过,您可以执行以下操作:

var combinedArrayOfPlanets = [...this.state.planets];

此外,您应该以与在初始状态下创建行星的方式相同的方式从商店中获取行星,而不是:

planets:state.requestPlanets.planets,

应为:

planets:state.planets,

这样,您将从减速器中获得行星,但不会从.json文件中获得多余的行星。我建议您在将它们保存到商店之前,从减速器的.json中添加这些额外的行星。