Reputation: 1176
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!
Upvotes: 0
Views: 4180
Reputation: 5598
AsyncStorage
returns a promise. Therefore when you call to retrieve items in componentDidMount
, the code will run passed the .then
even before the values are retrieved.
My suggestion is that you give listItem some dummy objects so that it is not undefined the first it is called.
Second suggestion would be use await
instead of .then
and use a helper function when calling listenItem.map so that it's not called until values have been loaded.
Upvotes: 0
Reputation: 445
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
.
Upvotes: 1