【问题标题】:TypeError: undefined is not a function (near '...todos.map...')TypeError: undefined is not a function ('...todos.map...' 附近)
【发布时间】:2021-11-11 02:15:53
【问题描述】:

我正在尝试在 useState 挂钩中使用 ASyncStorage 从存储中加载数据(如果存在)。 我在 map 函数中渲染 todos,但在此之前我正在检查 todos 是未定义还是 []。 如果数据不存在但未定义,则逻辑应将 [] 返回到 useState!

Here is an image of the error

代码如下:

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

  const [todos, setTodos] = useState(async () => {
    try {
      const value = await AsyncStorage.getItem('@MySuperStore:key');
      // We have data!!
      return value ? JSON.parse(value) : [];
    } catch (error) {
      // Error retrieving data
      console.log(error);
    }
  });

  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(newTodos).then(_retrieveData());

      // setTodos(newTodos);
    }
  };

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

  const _storeData = async (value) => {
    try {
      await AsyncStorage.setItem('@MySuperStore:key', JSON.stringify(value));
    } catch (error) {
      // Error saving data
      console.log(error);
    }
  };

  const _retrieveData = async () => {
    try {
      const value = await AsyncStorage.getItem('@MySuperStore:key');
      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 === [] || todos === undefined ? (
            <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>
  );
}

【问题讨论】:

  • === [] 永远不会是真的,因为比较是通过引用进行的,但这不是问题。请注意它说的是undefined is not a function 而不是Cannot read properties of undefined (reading 'map'),所以显然todos 不是未定义的,但也没有属性map,这意味着它是something 但可能不是数组。检查你的开发工具它实际上是什么。也许这是一个承诺。
  • 这个错误其实是来自useState钩子里面try-catch的catch块。 App.js:22 Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'getItem')
  • 你一个权利最初的承诺是返回的。

标签: javascript reactjs react-native react-hooks


【解决方案1】:

我不确定为什么todos 的默认状态会使用异步函数,这对我来说没有意义。相反,我会做const [todos, setTodos] = useState([]); 并利用useEffect 挂钩类似于此的东西:

useEffect(() => {
  (async () => {
      try {
      const value = await AsyncStorage.getItem('@MySuperStore:key');
      // We have data!!
      setTodos(value ? JSON.parse(value) : [])
    } catch (error) {
      // Error retrieving data
      console.log(error);
    }
  })();
},[]);

【讨论】:

  • 问题是 getItem 最初返回了一个承诺。一旦我检查了错误就解决了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-24
  • 2021-06-21
  • 1970-01-01
  • 2014-08-15
  • 2015-01-14
相关资源
最近更新 更多