简体   繁体   中英

React Native FlatList Object displaying

I have the below object that I am retrieving from the AsyncStorage, and I want to display it in a FlatList but I am getting the following error:

Invariant Violation: Invariant Violation: Invariant Violation: Invariant Violation: Tried to get frame for out of range index NaN

My JSON format is:

Object {
  "44": Object {
    "pro_id": "44",
    "pro_img": "url",
    "pro_name": " S4 ",
  },
  "52": Object {
    "pro_id": "52",
    "pro_img": "url",
    "pro_name": " S4 ",

  },
}

The JSON above is retrieved from AsyncStorage like so:

retrieveData = async () => {

    try {
       await AsyncStorage.getItem('userFavorites')
       .then(req => JSON.parse(req))
       .then(json => this.setState({ favPro:json }))

    } catch (error) {

    } 
}

My method for rendering items in the FlatList is defined like this:

 fav = ({ item }) => {
    return (
      <View>
      <Text>{item.pro_id+ item.pro_name}</Text>
      </View>
    )
}

Finally, I render the FlatList as follows:

<FlatList
          data={this.state.favPro}
          renderItem={this.fav}
          keyExtractor={item => item.pro_id}
        />

How I can display my JSON data using the FlatList component?

The FlatList component expects an array input for the data prop. Based on your JSON format, it appears you're passing in an object rather than an array.

Consider the following adjustment to your render method:

// Convert object to array based on it's values. If favPro not 
// valid (ie during network request, default to an empty array)
const data = this.state.favPro ? Object.values(this.state.favPro) : []

<FlatList
  data={data}
  renderItem={this.fav}
  keyExtractor={item => item.pro_id}
/>

You're using async / await incorrectly. Instead of calling .then you assign your call to await to a variable (or don't assign it if it does not return a value) and wrap the call (or calls) to await in a try / catch block. The await keyword will automatically handle resolve and reject so you get the appropriate information.

retrieveData = async () => {
  try {
    const data = JSON.parse(await AsyncStorage.getItem("userFavorites"))
    this.setState({ favPro: data })
  } catch (error) {
    console.error(error)
    this.setState({ favPro: [] })
  }
}

You also need to pass an array, the shape of your data looks like an object, but it should be an array of objects. This is not a terribly difficult transformation and I can provide a helper function if you need it.

edit: if you need to convert an object into an array, you can use the reduce function

const data = {
  '44': { a: 2 },
  '55': { b: 3 },
}

const dataArr = Object.keys(data).reduce(
  (arr, key) => arr.concat(data[key]),
  []
)

By using Object.keys we can each object by name. Then call reduce and the array returned by Object.keys , passing a function as the first argument, and an empty array as the second argument. The second argument is automatically passed to the function as the first argument, arr , and the second argument of the function we pass is the key of the object. Then it's just a matter of adding the objects to the array using concat .

Array.reduce can seem a little overwhelming at first but it's a very powerful method and you can get a lot done with it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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