简体   繁体   English

将数据加载到 React Native FlatList

[英]Loading data into a React Native FlatList

I fully admit that I'm pretty new to Reactive Native at this point so I anticipate this being an easy answer and a potentially stupid question :) In fact, this may not be a RN issue per se, as I'll explain below.我完全承认此时我对 Reactive Native 还很陌生,所以我预计这是一个简单的答案,也是一个可能很愚蠢的问题:) 事实上,这本身可能不是 RN 问题,我将在下面解释。

What I have is the following code:我所拥有的是以下代码:

class MyScreen extends React.Component {

  constructor(inProps) {
    super(inProps);
    this.state = { listData : [ ] };
  }

  render() { return (
    <View>
      <FlatList data={ this.state.listData }
        renderItem={ ({item}) =>
          <Text>{item.firstName} {item.lastName}</Text>
        }
      />
    </View>
  );  }

  async componentDidMount() {
    const data = [ ];
    let keys = await AsyncStorage.getAllKeys();
    keys.forEach(async function(inKey) {
      let obj = await AsyncStorage.getItem(inKey);
      obj = JSON.parse(obj);
      data.push(obj);
    });
    this.setState({ listData : data });
  };

}

The goal is simply to load the data from AsyncStorage and dump it in the list.目标只是从 AsyncStorage 加载数据并将其转储到列表中。 Fairly basic it would seem, right?看起来很基本,对吧? Unfortunately, I can't get it to work: the list is empty.不幸的是,我无法让它工作:列表是空的。

Now, to cover the stupid things: yes, there is indeed data stored and yes, it's in the correct form (I know this because if I simply grab ONE SPECIFIC item and push() it into data then it appears in the list as expected).现在,为了掩盖愚蠢的事情:是的,确实存储了数据,是的,它的格式正确(我知道这一点,因为如果我只是简单地获取一个特定的项目并将其 push() 到数据中,那么它会按预期出现在列表中)。

In fact, I know what the problem is: it's that the setState() call is executing before the keys.forEach() call completes.事实上,我知道问题是什么:这是 setState() 调用在 keys.forEach() 调用完成之前执行。 I know this because if I replace the setState() call with this:我知道这一点,因为如果我用这个替换 setState() 调用:

setTimeout(function() {
  this.setState({ listData : data });
}.bind(this), 1000);

...then suddenly my list is populated as expected (I can also throw some console.log()'s in there and see that the one after the keys.forEach() call actually executes BEFORE those inside the keys.forEach()). ...然后突然我的列表按预期填充(我也可以在那里抛出一些 console.log() 并看到 keys.forEach() 调用之后的那个实际上在 keys.forEach() 内部的那些之前执行)。 I also know that obviously the getItem() call is waiting before the JSON.parse() is called, otherwise this wouldn't work at all.我也知道显然 getItem() 调用在 JSON.parse() 被调用之前等待,否则这根本不起作用。

In other words: I know this is caused by the asynchronous nature of this code.换句话说:我知道这是由这段代码的异步性质引起的。 What I can't seem to figure out is how to write it properly to avoid this.我似乎无法弄清楚如何正确编写它以避免这种情况。

I'm looking at it and I'm thinking "well, keys.forEach() is a blocking call, so how could it possibly not complete before the setState() call, ESPECIALLY given the async usage on the keys.forEach() callback AND the await usage on the getItem() call inside?"... the only thought I had was to drop an async in front of the keys.forEach() call, but that doesn't make any difference.我在看它,我在想“好吧,keys.forEach() 是一个阻塞调用,所以它怎么可能在 setState() 调用之前无法完成,特别是考虑到 keys.forEach() 上的异步用法回调和内部 getItem() 调用的 await 用法?”...我唯一的想法是在 keys.forEach() 调用前删除异步,但这没有任何区别。

So, it seems to be a basic JavaScript question in essence, but I can't seem to solve it... but on the other hand, I'm not sure if I'm trying to do this in a way that I fundamentally shouldn't be in RN land and maybe THAT'S the real problem.所以,它本质上似乎是一个基本的 JavaScript 问题,但我似乎无法解决它......但另一方面,我不确定我是否试图以一种我从根本上不应该在 RN 土地上,也许这才是真正的问题。

Note that the data has to be pulled dynamically from AsyncStorage because of the flow through the application (adds are done on another screen), so it seems to me that trying to load it in componentDidMount() makes sense, I'm just getting hung up with the asynchronous nature of the calls involved.请注意,由于流经应用程序(添加在另一个屏幕上完成),必须从 AsyncStorage 动态提取数据,所以在我看来,尝试在 componentDidMount() 中加载它是有道理的,我只是被挂了了解所涉及调用的异步性质。

Any suggestions?有什么建议?

Thanks!谢谢!

EDIT: I should also mention that I know one way I can solve this is to just remove the asynchronous nature entirely: rather than storing individual data items, instead store everything in a single object in AsyncStorage.编辑:我还应该提到,我知道我可以解决这个问题的一种方法是完全删除异步性质:而不是存储单个数据项,而是将所有内容存储在 AsyncStorage 中的单个对象中。 Then I can read the ONE item, which would be an array (or would contain an array), then the only asynchronous part is the getItem() call, but I can use the callback version of that and make it work that way... and I'm not against that approach at all, but at this point I really want to understand what I'm doing wrong if for no other reason than to learn something because this seems like it SHOULD work :)然后我可以读取一个项目,它是一个数组(或包含一个数组),然后唯一的异步部分是 getItem() 调用,但我可以使用它的回调版本并使其以这种方式工作.. .而且我根本不反对这种方法,但在这一点上,我真的很想了解我做错了什么,如果不是为了学习一些东西,因为这似乎应该有效:)

keys.forEach execute the code in its own scope (in its own callback function), and that breaks your async / await pair. keys.forEach在它自己的范围内(在它自己的回调函数中)执行代码,这会破坏你的async / await对。

Do this instead:改为这样做:

for (let inKey of keys) {
    let obj = await AsyncStorage.getItem(inKey);
    obj = JSON.parse(obj);
    data.push(obj);   
}

If you really want forEach , you have to write your own version that returns Promise , so you can hook await on it for example:如果你真的想要forEach ,你必须编写自己的版本来返回Promise ,这样你就可以在它上面await例如:

await keys.awaitableForEach(async function(inKey) {

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM