Wat is AsyncStorage?

AsyncStorage is een simpele key-value storage voor React Native. Het slaat data lokaal op het apparaat op, zelfs als de app wordt afgesloten.

Wanneer AsyncStorage gebruiken?

  • User preferences (dark mode, taal)
  • Login tokens bewaren
  • Offline data caching
  • Onboarding status (eerste keer app open)
  • Eenvoudige app settings

Niet gebruiken voor:

  • Gevoelige data (wachtwoorden) - gebruik SecureStore
  • Grote datasets (>6MB) - gebruik SQLite
  • Complexe queries - gebruik een database

Installatie

Installeer AsyncStorage via Expo:

npx expo install @react-native-async-storage/async-storage

Import

import AsyncStorage from '@react-native-async-storage/async-storage';

Data Opslaan

Gebruik setItem() om data op te slaan. Het is een async functie!

String Opslaan

import AsyncStorage from '@react-native-async-storage/async-storage';

const saveData = async () => {
  try {
    await AsyncStorage.setItem('username', 'Jan');
    console.log('Data opgeslagen!');
  } catch (error) {
    console.error('Error:', error);
  }
};

In Component

import { useState } from 'react';
import { View, TextInput, Pressable, Text, StyleSheet } from 'react-native';
import AsyncStorage from '@react-native-async-storage/async-storage';

export default function App() {
  const [name, setName] = useState('');

  const saveName = async () => {
    try {
      await AsyncStorage.setItem('username', name);
      alert('Naam opgeslagen!');
    } catch (error) {
      console.error('Error:', error);
    }
  };

  return (
    <View style={styles.container}>
      <TextInput
        style={styles.input}
        placeholder="Naam"
        value={name}
        onChangeText={setName}
      />
      
      <Pressable style={styles.button} onPress={saveName}>
        <Text style={styles.buttonText}>Opslaan</Text>
      </Pressable>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    padding: 20,
  },
  input: {
    borderWidth: 1,
    borderColor: '#ddd',
    padding: 10,
    borderRadius: 5,
    marginBottom: 10,
  },
  button: {
    backgroundColor: '#007AFF',
    padding: 15,
    borderRadius: 8,
    alignItems: 'center',
  },
  buttonText: {
    color: 'white',
    fontWeight: 'bold',
  },
});

Let op: AsyncStorage slaat alleen strings op! Voor objecten gebruik je JSON.stringify().

Data Ophalen

Gebruik getItem() om data op te halen.

String Ophalen

const loadData = async () => {
  try {
    const value = await AsyncStorage.getItem('username');
    if (value !== null) {
      console.log('Naam:', value);
    } else {
      console.log('Geen data gevonden');
    }
  } catch (error) {
    console.error('Error:', error);
  }
};

Bij Component Mount

import { useState, useEffect } from 'react';
import { View, Text, StyleSheet } from 'react-native';
import AsyncStorage from '@react-native-async-storage/async-storage';

export default function App() {
  const [username, setUsername] = useState('');

  useEffect(() => {
    loadUsername();
  }, []);

  const loadUsername = async () => {
    try {
      const value = await AsyncStorage.getItem('username');
      if (value !== null) {
        setUsername(value);
      }
    } catch (error) {
      console.error('Error:', error);
    }
  };

  return (
    <View style={styles.container}>
      <Text style={styles.text}>
        Welkom terug, {username || 'Gast'}!
      </Text>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  text: {
    fontSize: 24,
  },
});

Data Verwijderen

Eén Item Verwijderen

const removeData = async () => {
  try {
    await AsyncStorage.removeItem('username');
    console.log('Data verwijderd!');
  } catch (error) {
    console.error('Error:', error);
  }
};

Alles Verwijderen

const clearAll = async () => {
  try {
    await AsyncStorage.clear();
    console.log('Alles verwijderd!');
  } catch (error) {
    console.error('Error:', error);
  }
};

Let op: clear() verwijdert alle data! Gebruik dit alleen als je zeker weet dat je alles wilt verwijderen (bijvoorbeeld bij logout).

Objecten Opslaan

Gebruik JSON.stringify() om objecten op te slaan en JSON.parse() om ze op te halen.

Object Opslaan

const saveUser = async (user) => {
  try {
    const jsonValue = JSON.stringify(user);
    await AsyncStorage.setItem('user', jsonValue);
    console.log('User opgeslagen!');
  } catch (error) {
    console.error('Error:', error);
  }
};

// Gebruik
const user = {
  name: 'Jan',
  email: 'jan@example.com',
  age: 25,
};

saveUser(user);

Object Ophalen

const loadUser = async () => {
  try {
    const jsonValue = await AsyncStorage.getItem('user');
    const user = jsonValue != null ? JSON.parse(jsonValue) : null;
    
    if (user) {
      console.log('Name:', user.name);
      console.log('Email:', user.email);
    }
  } catch (error) {
    console.error('Error:', error);
  }
};

Array Opslaan

const saveTodos = async (todos) => {
  try {
    const jsonValue = JSON.stringify(todos);
    await AsyncStorage.setItem('todos', jsonValue);
  } catch (error) {
    console.error('Error:', error);
  }
};

const loadTodos = async () => {
  try {
    const jsonValue = await AsyncStorage.getItem('todos');
    return jsonValue != null ? JSON.parse(jsonValue) : [];
  } catch (error) {
    console.error('Error:', error);
    return [];
  }
};

Volledig Voorbeeld - Todo App

import { useState, useEffect } from 'react';
import { View, TextInput, Pressable, Text, FlatList, StyleSheet } from 'react-native';
import AsyncStorage from '@react-native-async-storage/async-storage';

export default function TodoApp() {
  const [text, setText] = useState('');
  const [todos, setTodos] = useState([]);

  // Load todos bij app start
  useEffect(() => {
    loadTodos();
  }, []);

  // Save todos elke keer als ze wijzigen
  useEffect(() => {
    saveTodos();
  }, [todos]);

  const loadTodos = async () => {
    try {
      const jsonValue = await AsyncStorage.getItem('todos');
      if (jsonValue !== null) {
        setTodos(JSON.parse(jsonValue));
      }
    } catch (error) {
      console.error('Error loading todos:', error);
    }
  };

  const saveTodos = async () => {
    try {
      const jsonValue = JSON.stringify(todos);
      await AsyncStorage.setItem('todos', jsonValue);
    } catch (error) {
      console.error('Error saving todos:', error);
    }
  };

  const addTodo = () => {
    if (text.trim()) {
      setTodos([
        ...todos,
        { id: Date.now().toString(), text, completed: false },
      ]);
      setText('');
    }
  };

  const toggleTodo = (id) => {
    setTodos(
      todos.map((todo) =>
        todo.id === id ? { ...todo, completed: !todo.completed } : todo
      )
    );
  };

  const deleteTodo = (id) => {
    setTodos(todos.filter((todo) => todo.id !== id));
  };

  return (
    <View style={styles.container}>
      <Text style={styles.title}>My Todos</Text>

      <View style={styles.inputContainer}>
        <TextInput
          style={styles.input}
          placeholder="Nieuwe todo..."
          value={text}
          onChangeText={setText}
          onSubmitEditing={addTodo}
        />
        <Pressable style={styles.addButton} onPress={addTodo}>
          <Text style={styles.addButtonText}>+</Text>
        </Pressable>
      </View>

      <FlatList
        data={todos}
        keyExtractor={(item) => item.id}
        renderItem={({ item }) => (
          <View style={styles.todoItem}>
            <Pressable
              style={styles.todoText}
              onPress={() => toggleTodo(item.id)}
            >
              <Text
                style={[
                  styles.text,
                  item.completed && styles.completedText,
                ]}
              >
                {item.text}
              </Text>
            </Pressable>
            
            <Pressable onPress={() => deleteTodo(item.id)}>
              <Text style={styles.deleteButton}>X</Text>
            </Pressable>
          </View>
        )}
      />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 20,
    backgroundColor: '#f5f5f5',
  },
  title: {
    fontSize: 32,
    fontWeight: 'bold',
    marginBottom: 20,
    color: '#333',
  },
  inputContainer: {
    flexDirection: 'row',
    marginBottom: 20,
  },
  input: {
    flex: 1,
    borderWidth: 1,
    borderColor: '#ddd',
    padding: 12,
    borderRadius: 8,
    backgroundColor: 'white',
    marginRight: 10,
  },
  addButton: {
    backgroundColor: '#007AFF',
    width: 50,
    borderRadius: 8,
    justifyContent: 'center',
    alignItems: 'center',
  },
  addButtonText: {
    color: 'white',
    fontSize: 24,
    fontWeight: 'bold',
  },
  todoItem: {
    flexDirection: 'row',
    alignItems: 'center',
    backgroundColor: 'white',
    padding: 15,
    borderRadius: 8,
    marginBottom: 10,
  },
  todoText: {
    flex: 1,
  },
  text: {
    fontSize: 16,
  },
  completedText: {
    textDecorationLine: 'line-through',
    color: '#999',
  },
  deleteButton: {
    color: 'red',
    fontSize: 18,
    fontWeight: 'bold',
    padding: 5,
  },
});

Dit voorbeeld toont:

  • Todos laden bij app start met useEffect
  • Todos opslaan elke keer als ze wijzigen
  • JSON.stringify() en JSON.parse() voor arrays
  • Todo toevoegen, togglen en verwijderen
  • Data blijft bewaard zelfs als app wordt afgesloten!

Samenvatting

setItem()

Data opslaan

getItem()

Data ophalen

removeItem()

Data verwijderen

JSON.stringify()

Objecten opslaan

Je hebt nu geleerd:

  • AsyncStorage installeren en importeren
  • Data opslaan met setItem()
  • Data ophalen met getItem()
  • Data verwijderen met removeItem() en clear()
  • Objecten en arrays opslaan met JSON
  • Complete todo app met persistente data