React-Native异步Array.map = undefined不是Object

时间:2019-03-13 10:52:58

标签: javascript react-native async-await

我尝试使用ReactNative创建我的第一个混合应用程序。我的Array.map有问题...

class HomeScreen extends React.Component {

  state = {
    isLoading: false,
    captured: false,
    wished: false,
    exchanged: false,
    data: {}
  };

  async getPokemonFromApiAsync() {
    try {
      this.setState({isLoading: true});
      let response = await fetch('https://pokeapi.co/api/v2/pokemon/?limit=0&offset=20');
return this.setState({
        isLoading: false,
        data: await response.json()
       });
    } catch (error) {
      console.error(error);
  }

  (...)    

  componentWillMount() {
      this.getPokemonFromApiAsync()
  }

  (...)

  result = (result = this.state.data.results) => {
      console.log('test', this.state.data);
      return (
         <View>

             (...)

             result.map( (item, index) => {

             (...)

             }
         </View>
      )
  } 
}

我不明白,为什么我的函数getPokemonFromApiAsync为空。 iOS模拟器返回TypeError:未定义不是对象(正在评估'result.map')

在添加类似以下的构造函数时:

constructor(props) {
   super(props)
   this.getPokemonFromApiAsync = This.getPokemonFromApiAsync.bind(this)
}

控制台中有很多错误:

警告:无法在尚未安装的组件上调用%s。这是一项禁止操作的操作,但可能表明您的应用程序中存在错误。而是直接分配给this.state或在%s组件中使用所需状态定义一个state = {};类属性。setState,HomeScreen

对我来说,这很正常...

异步Http请求的良好生命周期是什么?

4 个答案:

答案 0 :(得分:0)

使用axios库github link

的最佳方法
contract AddressBook {
    mapping(address => address[]) private _addresses;
    mapping(address => mapping(address => string)) private _aliases;

    function getAddresses() public view  returns (address[]) {
        return _addresses[msg.sender];
    }    
    function addAddress(address addr, string _alias) public payable {
        _addresses[msg.sender].push(addr);
        _aliases[msg.sender][addr] = _alias;
    }

    function removeAddress(address addr) public payable {
        uint length = _addresses[msg.sender].length;
        for(uint i = 0; i < length; i++) {
            if (addr == _addresses[msg.sender][i]) {
                if (1 < _addresses[msg.sender].length && i < length-1) {
                    _addresses[msg.sender][i] = _addresses[msg.sender][length-1];
                }
                delete _addresses[msg.sender][length-1];
                _addresses[msg.sender].length--;
                delete _aliases[msg.sender][addr];
                break;
            }
        }
    }

    function getAlias(address addr) public view returns (string) {
        return _aliases[msg.sender][addr];
    }
}

最后,每周下载量超过4,000,000+ Github开始50,000 +

答案 1 :(得分:0)

更好的方法是使用“ then”解决您的诺言时实现状态值。

let response = fetch('https://pokeapi.co/api/v2/pokemon/?limit=0&offset=20')
  .then((response) => {
     this.setState({
       isLoading: false,
       data: response.json()
     });
  });

也许您可以在Promise回调中处理数据(result.map)并将结果直接插入组件中。

顺便说一句,XHR调用通常以componentDidMount方法处理。

答案 2 :(得分:0)

您的错误是由您如何将初始data设置为状态引起的。

您已将其设置为:

state = {
  isLoading: false,
  captured: false,
  wished: false,
  exchanged: false,
  data: {} // <- here you define it as an object, with no parameters
};

您应该将其设置为带有results参数的对象。因此,您的初始状态应为

state = {
  isLoading: false,
  captured: false,
  wished: false,
  exchanged: false,
  data: { results: [] } // <- here you should define the results inside the object
};

出现错误的原因:

TypeError: Undefined is not an object (evaluating 'result.map')

是因为在初始渲染中,在获取响应返回之前,它试图在map之上的this.state.data.results上不存在。您需要确保状态中的results有一个初始值。

那应该停止初始错误,但是您必须确保为data保存的状态也是一个数组,否则您将继续遇到相同的错误。


componentWillMount已被弃用,您应该使用componentDidMount

此外,您在componentWillMount内部调用异步函数时,还应通过以下方式重构它:

async componentDidMount() {
  await this.getPokemonFromApiAsync()
}

这样,直到获取请求完成后才进行安装。


我还将重构您的getPokemonFromApiAsync,以便您在尝试将其设置为状态之前获得response.json()。您也不需要return语句,因为this.setState不返回任何内容。

async getPokemonFromApiAsync() {
  try {
    this.setState({isLoading: true});
    let response = await fetch('https://pokeapi.co/api/v2/pokemon/?limit=0&offset=20');
    let data = await response.json(); // get the data 
    this.setState({
      isLoading: false,
      data: data // now set it to state
    });
  } catch (error) {
    console.error(error);
}

小吃:

这是一个非常简单的小吃,显示了https://snack.expo.io/@andypandy/pokemon-fetch的代码正常工作

小吃代码:

export default class App extends React.Component {

  state = {
    isLoading: false,
    captured: false,
    wished: false,
    exchanged: false,
    data: { results: [] } // <- here you should define the results inside the object
  };

  getPokemonFromApiAsync = async () => {
    try {
      this.setState({ isLoading: true });
      let response = await fetch('https://pokeapi.co/api/v2/pokemon/?limit=0&offset=20');
      let data = await response.json(); // get the data
      this.setState({
        isLoading: false,
        data: data // now set it to state
      });
    } catch (error) {
      console.error(error);
    }
  }

  async componentDidMount () {
    await this.getPokemonFromApiAsync();
  }

  render () {
    return (
      <View style={styles.container}>
        {this.state.data.results.map(item => <Text>{item.name}</Text>)}
      </View>
    );
  }
}

答案 3 :(得分:0)

收到错误TypeError: Undefined is not an object (evaluating 'result.map')的原因是您从result获取了this.state.data.results,但是由于数据是异步的,因此在首次呈现时,数据就是{{ 1}}(因为您将其设置为状态),因此{}data.result,并且不能在未定义的地方使用undefined

要解决此问题,可以在呈现.map()之前检查其是否未定义。

data.result