Search code examples
javascriptreactjsreact-nativeasyncstorage

AsyncStorage.getItem in componentDidMount


I'm trying to create a simple to-do application to practice React-Native and I'm having trouble retrieving the items when the componentDidMount

The app state :

this.state = {
  task: "",
  tasks: []
};

When the user adds a new task handleAddTask runs and I attached the AsyncStorage.setItem as a callback for setState so that the tasks array is saved to the storage after the state is updated.

handleAddTask = () => {

  let notEmpty = this.state.task.trim().length > 0;
  if (notEmpty) {
    this.setState(
      prevState => {
        return {
          tasks: prevState.tasks.concat(prevState.task)
        };
      },() => {
        AsyncStorage.setItem("tasks", JSON.stringify(this.state.tasks));
      }
    );
  }

};

Similarly, when the user taps on a list item handleDelete runs, it removes the selected task from the tasks array and updates the AsyncStorage

handleDelete = index => {

  this.setState(
    prevState => {
      return {
        tasks: prevState.tasks.filter((place, i) => {
          return i !== index;
        })
      };
    },() => {
      AsyncStorage.setItem("tasks", JSON.stringify(this.state.tasks));
    }
  );

};

However, I'm trying to retreive the tasks array from AsyncStorage inside componentDidMount like so :

componentDidMount() {
  AsyncStorage.getItem("tasks")
    .then(value => {
      this.setState({ "tasks": value });
    })
    .done();
}

The way I'm displaying the tasks list is by passing the state through a component called List:

<List
  listItems={this.state.tasks}
  handleDelete={this.handleDelete}
/>

Inside List.js I'm mapping through the tasks array:

export default class List extends Component {

  render() {

    const namesOutput = this.props.listItems.map((name, i) => (
      <TouchableOpacity
        key={i}
        onPress={() => this.props.handleDelete(i)}
        activeOpacity={0.6}
        style={styles.listItemContainer}
      >
        <Text style={styles.listItemText}>{name}</Text>
      </TouchableOpacity>
    ));

    return (
      <View style={styles.listContainer}>
        <ScrollView>{namesOutput}</ScrollView>
      </View>
    );
  }

}

And I get the following error:

TypeError: undefined is not a function (evaluating 'this.props.listItem.map')

I've been commenting lines here and there to see where the problems is and I can only assume that it's in the way I'm getting the items in componentDidMount

Is there something about asynchronous JavaScript that I missed? Also, do I have to JSON.parse when I do getItem ? If anyone has additional feedback about my code in general I'd love to learn more.

Thanks in advance!


Solution

  • You saved to storage JSON.stringify() values, then used it without using JSON.parse(). I think that this is the problem. You can check it by stop on break point on your List component render before it maps its props, and detect that your props.listItems isn't array after componentDidMount.