首页 > 解决方案 > 使用 AsyncStorage 时未加载待办事项

问题描述

我正在尝试使用 AsyncStorage 从 useEffect 挂钩中获取我的待办事项。如果没有待办事项(意思是待办事项 === [])然后文本组件显示“添加待办事项”。

博览会中的应用图像

最初,待办事项在 useState 挂钩中设置为“[]”。当在 onPress 调用 addItem() 方法时,todos 没有加载。

我不知道为什么会这样……

export default function App() {
  const [todo, setTodo] = useState('');
  const [todos, setTodos] = useState([]);

  useEffect(() => {
    _retrieveData();
  }, [todos]);

  const addItem = (newTodo) => {
    if (newTodo.length === 0) {
      Alert.alert(
        'Enter a String',
        'You have entered a string with 0 characters',
        [{ text: 'Okay', style: 'default' }]
      );
    } else {
      console.log(newTodo);
      let newTodos = [newTodo, ...todos];
      setTodo('');
      _storeData(JSON.stringify(newTodos));
    }
  };

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

  const _storeData = async (value) => {
    try {
      await AsyncStorage.setItem('TASKS', value);
    } catch (error) {
      // Error saving data
      console.log(e);
    }
  };

  const _retrieveData = async () => {
    try {
      const value = await AsyncStorage.getItem('TASKS');
      if (value !== null) {
        // We have data!!
        setTodos(JSON.parse(value));

        console.log(value);
      }
    } catch (error) {
      // Error retrieving data
      console.log(error);
    }
  };

  return (
    <TouchableWithoutFeedback
      onPress={() => {
        Keyboard.dismiss();
      }}
    >
      <View style={styles.outerContainer}>
        <Text style={styles.header}>TODO</Text>
        <View style={styles.container}>
          <TextInput
            placeholder='new todo'
            style={styles.input}
            value={todo}
            onChangeText={(text) => {
              setTodo(text);
            }}
          ></TextInput>
          <Button title='Add' onPress={() => addItem(todo)}></Button>
        </View>
        <ScrollView style={styles.scrollView}>
          {todos === [] ? (
            <View>
              <Text>Add a todo!</Text>
            </View>
          ) : (
            todos.map((todo, idx) => (
              <View style={styles.todo} key={idx}>
                <Text style={styles.todoText}>{todo}</Text>
                <View style={styles.delete}>
                  <Button
                    color='red'
                    title='Delete'
                    onPress={() => deleteTodo(idx)}
                  ></Button>
                </View>
              </View>
            ))
          )}
        </ScrollView>
      </View>
    </TouchableWithoutFeedback>
  );
}

标签: javascriptreactjsreact-native

解决方案


不要使用传递todonewTodo,因为setState不会async立即执行,因此您可以使用当前设置todo的值而不是传递旧值,

  const addItem = (newTodo) => {
    if (todo.length === 0) {
      Alert.alert(
        'Enter a String',
        'You have entered a string with 0 characters',
        [{ text: 'Okay', style: 'default' }]
      );
    } else {
      console.log(todo);
      let newTodos = [todo, ...todos];
      setTodo('');
      _storeData(JSON.stringify(newTodos));
      setTodos(newTodos);
    }
  };

推荐阅读