TypeError:无法读取未定义的 WatermelonDB React Native 的属性“集合”

问题描述 投票:0回答:1

我正在开发一个 React Native 应用程序,使用 WatermelonDB 作为我的数据库框架。我遵循 Watermelons 文档制作模型、模型、数据库和助手;使用 withObserables 来显示数据,但它不断在标题中抛出错误。我仍然找不到任何解决方案来解决我的问题,我在这里向其他开发人员寻求帮助。这是我第一次使用 WatermelonDB。

log of an error on android emulator shows that error is at HomeScreen.js

应用程序.tsx

import * as React from 'react';
import MainContainer from './navigation/MainContainer';
import database, {initializeDatabase} from './model/database_users';

function App() {
  React.useEffect(() => {
    // Initialize the database when the component mounts
    initializeDatabase()
      .then(() => {
        console.log('Database initialization complete');
        // Continue with the rest of your application logic
      })
      .catch(error => {
        console.error('Error initializing database:', error);
      });
  }, []);
  return <MainContainer />;
}

export default App;

seedDatabase.js

import {User} from './model/model'; // Import your WatermelonDB model

async function seedDatabase() {
  // Check if there are any users in the database
  const existingUsersCount = await User.query().fetchCount();

  // If the database is empty, insert the initial users
  if (existingUsersCount === 0) {
    try {
      await User.withDatabase(async database => {
        // Insert each user into the database
        for (const userData of initialUsers) {
          await database.action(async () => {
            await User.create(user => {
              user.name = userData.name;
              user.email = userData.email;
              user.password = userData.password;
            });
          });
        }
      });
      console.log('Seed data inserted successfully');
    } catch (error) {
      console.error('Error inserting seed data:', error);
    }
  } else {
    console.log('Database already seeded');
  }
}

export default seedDatabase;

./model/model.js

import {Model} from '@nozbe/watermelondb';
import {field, text} from '@nozbe/watermelondb/decorators';

class User extends Model {
  static table = 'users';
  static associations = {
    sites: {type: 'has_many', foreignKey: 'author'},
  };
  @text('name') name;
  @text('email') email;
  @text('password') password;
}

class Site extends Model {
  static table = 'sites';
  static associations = {
    user: {type: 'belongs_to', key: 'author'},
  };
  @text('site_id') site_id;
  @text('txt') txt;
  @text('image') image;
  @relation('user', 'author') author;
}

.model/shema.js

import {appSchema, tableSchema} from '@nozbe/watermelondb';

const shema = appSchema({
  version: 4,
  tables: [
    tableSchema({
      name: 'users',
      columns: [
        {name: 'name', type: 'string', isIndexed: true},
        {name: 'password', type: 'string'},
        {name: 'email', type: 'string'},
      ],
    }),
    tableSchema({
      name: 'sites',
      columns: [
        {name: 'site_id', type: 'string', isIndexed: true},
        {name: 'txt', type: 'string'},
        {name: 'image', type: 'string'},
        {name: 'author', type: 'string'},
      ],
    }),
  ],
});

database_users.js

import {Database} from '@nozbe/watermelondb';
import SQLiteAdapter from '@nozbe/watermelondb/adapters/sqlite';

import {User} from './model';
import {shema} from './shema';
import migrations from './migrations';

import seedDatabase from '../seedDatabase';

const adapter = new SQLiteAdapter({
  migrations,
  shema,
  jsi: true, // enable if Platform.OS === 'ios'
});

const database = new Database({
  adapter,
  modelClasses: [User],
});

// Initialize the database
export async function initializeDatabase() {
  try {
    await database.adapter.initialize();
    console.log('Database initialized');
  } catch (error) {
    console.error('Error initializing database:', error);
    throw error; // Propagate the error if initialization fails
  }
}

export default database;

./navigation/components/UserListItem.js

import {Button, StyleSheet, Text, View} from 'react-native';
import {deleteUser} from '../../model/helpers';
import {withObservables} from '@nozbe/watermelondb/react';

function UserListItem({user}) {
  return (
    <View key={user.name} style={styles.userRow}>
      <View style={styles.button}>
        <Button title="DEL" onPress={() => deleteUser(user)} />
        {/* For demo simplicity when we update a record we just update its minPlayers */}
      </View>
      <Text>{user.name} - </Text>
    </View>
  );
}

const enchance = withObservables(['user'], ({user}) => ({
  user,
}));

UserListItem = enchance(UserListItem);
export default UserListItem;

const styles = StyleSheet.create({
  userRow: {flexDirection: 'row', alignItems: 'center', marginVertical: 8},
  button: {marginRight: 8, flexDirection: 'row'},
});

./navigation/screens/DetailsScreen.js

import * as React from "react";
import { View, Text } from "react-native";

export default function DetailsScreen({ navigation }) {
    return (
        <View style={{ flex: 1, alignItems: "center", justifyContent: "center" }}>
            <Text
                onPress={() => navigation.navigate("Home")}
                style={{ fontSize: 26, fontWeight: "bold" }}
            >
                Culturise
            </Text>
        </View>
    );
}

./navigation/screens/SearchScreen.js

import * as React from 'react';
import {
  StyleSheet,
  KeyboardAvoidingView,
  Platform,
  Keyboard,
} from 'react-native';
import {Searchbar} from 'react-native-paper';

export default function SearchScreen({navigation}) {
  const [searchQuery, setSearchQuery] = React.useState('');
  var [isSearching, setIsSearching] = React.useState(false);

  React.useEffect(() => {
    const keyboardDidShowListener = Keyboard.addListener(
      'keyboardDidShow',
      () => {
        setIsSearching(true);
      },
    );
    const keyboardDidHideListener = Keyboard.addListener(
      'keyboardDidHide',
      () => {
        setIsSearching(false);
      },
    );

    // makni listenere kada nema tipkovnice
    return () => {
      keyboardDidShowListener.remove();
      keyboardDidHideListener.remove();
    };
  }, []);
  return (
    <KeyboardAvoidingView
      style={styles.container}
      behavior={Platform.OS === 'ios' ? 'padding' : 'height'}>
      <Searchbar
        style={isSearching ? styles.bar1 : styles.bar}
        placeholder="Search"
        onChangeText={setSearchQuery}
        value={searchQuery}
        showLoading={true}
      />
    </KeyboardAvoidingView>
  );
}

const styles = StyleSheet.create({
  bar: {
    height: 60,
    position: 'relative',
    width: '90%',
    bottom: '-170%',
    //flex: 1,
    opacity: 1,
    marginRight: 'auto',
    marginLeft: 'auto',
    lineHeight: 44,
    borderTopLeftRadius: 40,
    borderTopRightRadius: 40,
    borderBottomRightRadius: 40,
    borderBottomLeftRadius: 40,
    backgroundColor: 'rgba(255, 255, 255, 1)',
    color: 'rgba(136, 136, 136, 1)',
    fontSize: 30,
    textAlign: 'left',
    fontFamily: 'Roboto',
    borderWidth: 1,
    borderColor: 'rgba(255, 255, 255, 1)',
    borderStyle: 'solid',
  },
  container: {
    flex: 1,
  },
  bar1: {
    height: 60,
    width: '90%',
    bottom: '-3%',
    opacity: 1,
    marginRight: 'auto',
    marginLeft: 'auto',
    lineHeight: 44,
    borderTopLeftRadius: 40,
    borderTopRightRadius: 40,
    borderBottomRightRadius: 40,
    borderBottomLeftRadius: 40,
    backgroundColor: 'rgba(255, 255, 255, 1)',
    color: 'rgba(136, 136, 136, 1)',
    fontSize: 30,
    textAlign: 'left',
    fontFamily: 'Roboto',
    borderWidth: 1,
    borderColor: 'rgba(255, 255, 255, 1)',
    borderStyle: 'solid',
  },
});

./navigation/screens/SettingsScreen.js

import {View, Text} from 'react-native';
import {User} from '../../model/model';

export default function SettingsScreen({navigation}) {
  return (
    <View style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}>
      <Text
        onPress={() => navigation.navigate('Home')}
        style={{fontSize: 26, fontWeight: 'bold'}}>
        {Settings}
      </Text>
    </View>
  );
}

./navigation/screens/HomeScreen.js

import * as React from 'react';
import {View, Text} from 'react-native';
import {withObservables} from '@nozbe/watermelondb/react';

//import {User} from '../../model/model';
import {UserListItem} from '../components/UserListItem';

function HomeScreenComponent({navigation, users}) {
  return (
    <View style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}>
      <Text
        onPress={() => navigation.navigate('Home')}
        style={{fontSize: 26, fontWeight: 'bold'}}>
        {users.map(user => (
          <UserListItem key={user.name} user={user} />
        ))}
      </Text>
    </View>
  );
}

const enhance = withObservables([], ({database}) => ({
  users: database.collections.get(User.table).query().observe(),
}));

const HomeScreen = enhance(HomeScreenComponent);

export default HomeScreen;

./navigation/MainContainer.js

import * as React from 'react';
import {Image} from 'react-native';
import {NavigationContainer} from '@react-navigation/native';
import {createBottomTabNavigator} from '@react-navigation/bottom-tabs';
import Feather from 'react-native-vector-icons/Feather';

// Screens
import HomeScreen from './screens/HomeScreen';
import DetailsScreen from './screens/DetailsScreen';
import SettingsScreen from './screens/SettingsScreen';
import SearchScreen from './screens/SearchScreen';

//Screen names
const homeName = 'Lucky';
const detailsName = 'Culturise';
const settingsName = 'Account';
const searchName = 'Search';

const Tab = createBottomTabNavigator();

function MainContainer() {
  return (
    <NavigationContainer>
      <Tab.Navigator
        initialRouteName={homeName}
        screenOptions={({route}) => ({
          tabBarIcon: ({color, size}) => {
            let iconName;
            let rn = route.name;

            if (rn === homeName) {
              iconName = 'lucky';
            } else if (rn === detailsName) {
              iconName = 'compass';
            } else if (rn === settingsName) {
              iconName = 'user';
            } else if (rn === searchName) {
              iconName = 'search';
            }

            if (iconName != 'lucky') {
              return <Feather name={iconName} size={size} color={color} />;
            } else {
              return (
                <Image
                  source={require('../assets/dice.png')}
                  style={{width: 24, height: 24}}
                />
              );
            }
          },
        })}
        tabBarOptions={{
          activeTintColor: 'black',
          inactiveTintColor: 'grey',
          labelStyle: {paddingBottom: 10, fontSize: 9},
          style: {padding: 10, height: 70},
        }}>
        <Tab.Screen name={homeName} component={HomeScreen} />
        <Tab.Screen name={detailsName} component={DetailsScreen} />
        <Tab.Screen name={searchName} component={SearchScreen} />
        <Tab.Screen name={settingsName} component={SettingsScreen} />
      </Tab.Navigator>
    </NavigationContainer>
  );
}

export default MainContainer;

错误的完整日志:

 TypeError: Cannot read property 'collections' of undefined

This error is located at:
    in withObservables[] (created by SceneView)
    in StaticContainer
    in EnsureSingleNavigator (created by SceneView)
    in SceneView (created by BottomTabView)
    in RCTView (created by View)
    in View (created by Screen)
    in RCTView (created by View)
    in View (created by Background)
    in Background (created by Screen)
    in Screen (created by BottomTabView)
    in RNSScreen
    in Unknown (created by InnerScreen)
    in Suspender (created by Freeze)
    in Suspense (created by Freeze)
    in Freeze (created by DelayedFreeze)
    in DelayedFreeze (created by InnerScreen)
    in InnerScreen (created by Screen)
    in Screen (created by MaybeScreen)
    in MaybeScreen (created by BottomTabView)
    in RNSScreenContainer (created by ScreenContainer)
    in ScreenContainer (created by MaybeScreenContainer)
    in MaybeScreenContainer (created by BottomTabView)
    in RNCSafeAreaProvider (created by SafeAreaProvider)
    in SafeAreaProvider (created by SafeAreaProviderCompat)
    in SafeAreaProviderCompat (created by BottomTabView)
    in BottomTabView (created by BottomTabNavigator)
    in PreventRemoveProvider (created by NavigationContent)
    in NavigationContent
    in Unknown (created by BottomTabNavigator)
    in BottomTabNavigator (created by MainContainer)
    in EnsureSingleNavigator
    in BaseNavigationContainer
    in ThemeProvider
    in NavigationContainerInner (created by MainContainer)
    in MainContainer (created by App)
    in App
    in RCTView (created by View)
    in View (created by AppContainer)
    in RCTView (created by View)
    in View (created by AppContainer)
    in AppContainer
    in AwesomeProject1(RootComponent), js engine: hermes
 ERROR  TypeError: Cannot read property 'collections' of undefined

This error is located at:
    in withObservables[] (created by SceneView)
    in StaticContainer
    in EnsureSingleNavigator (created by SceneView)
    in SceneView (created by BottomTabView)
    in RCTView (created by View)
    in View (created by Screen)
    in RCTView (created by View)
    in View (created by Background)
    in Background (created by Screen)
    in Screen (created by BottomTabView)
    in RNSScreen
    in Unknown (created by InnerScreen)
    in Suspender (created by Freeze)
    in Suspense (created by Freeze)
    in Freeze (created by DelayedFreeze)
    in DelayedFreeze (created by InnerScreen)
    in InnerScreen (created by Screen)
    in Screen (created by MaybeScreen)
    in MaybeScreen (created by BottomTabView)
    in RNSScreenContainer (created by ScreenContainer)
    in ScreenContainer (created by MaybeScreenContainer)
    in MaybeScreenContainer (created by BottomTabView)
    in RNCSafeAreaProvider (created by SafeAreaProvider)
    in SafeAreaProvider (created by SafeAreaProviderCompat)
    in SafeAreaProviderCompat (created by BottomTabView)
    in BottomTabView (created by BottomTabNavigator)
    in PreventRemoveProvider (created by NavigationContent)
    in NavigationContent
    in Unknown (created by BottomTabNavigator)
    in BottomTabNavigator (created by MainContainer)
    in EnsureSingleNavigator
    in BaseNavigationContainer
    in ThemeProvider
    in NavigationContainerInner (created by MainContainer)
    in MainContainer (created by App)
    in App
    in RCTView (created by View)
    in View (created by AppContainer)
    in RCTView (created by View)
    in View (created by AppContainer)
    in AppContainer
    in AwesomeProject1(RootComponent), js engine: hermes


最新尝试:尝试用seedDatabase函数填充数据库,没有解决问题

react-native watermelondb
1个回答
0
投票

查看错误

TypeError: Cannot read property 'collections' of undefined
可以很好地提示问题所在。

来自

./navigation/screens/HomeScreen.js

const enhance = withObservables([], ({database}) => ({
  users: database.collections.get(User.table).query().observe(),
}));

“数据库”参数未定义。

请注意,您没有在此处传递数据库

./navigation/MainContainer.js

<Tab.Screen name={homeName} component={HomeScreen} />

WatermelonDB 和 React Native 有几种方法来处理这个问题。我过去在使用 WatermelonDB 时所做的就是螺旋钻探。如果您这样做,在某些情况下您可能需要使用

this.props.database
,所以请注意这一点。

<Tab.Screen name={homeName} children={ () => <HomeScreen database={ database }/> }/>

您还可以使用提供商。 watermelonDB 文档 有一个关于其数据库提供程序的部分。虽然我建议阅读他们的文档以获取更多信息,但下面复制了一些代码。

import { DatabaseProvider } from '@nozbe/watermelondb/react'

render(
  <DatabaseProvider database={database}>
    { // rest of the app that needs the database }
  </DatabaseProvider>
)

有两种记录的使用数据库的方法

import { withDatabase, compose } from '@nozbe/watermelondb/react'

export default compose(
  withDatabase,
  withObservables([], ({ database }) => ({
    blogs: database.get('blogs').query(),
  }),
)(BlogList)

// Or

import { useDatabase } from '@nozbe/watermelondb/react'

const Component = () => {
   const database = useDatabase()
}
© www.soinside.com 2019 - 2024. All rights reserved.