Недавно я начал изучать React Context и ловушку и соответственно обновлять существующее приложение. Но столкнулся с проблемой, которую я не могу решить. Когда я использую useContext в своем компоненте, он выдает мне эту ошибку TypeError: Cannot read property 'state' of undefined
, я весь день искал в Интернете и пересмотрел еще несколько серий руководств, но не мог понять, в чем проблема, с которой я столкнулся, и как ее решить. Это. Так что, если кто-нибудь из вас, ребята, поможет мне с этим, это будет действительно полезно для меня. Вот мой код:
context. js
import React, { createContext, useReducer } from "react";
import AsyncStorage from '@react-native-community/async-storage';
export const AuthContext = createContext();
const initialState = {
isLoading: true,
newSession: false,
userToken: null
};
const createActions = dispatch => ({
signInPage: data => {
dispatch({ type: 'SIGN_IN_PAGE' });
},
signInAction: async data => {
const { student_id, password, database_name, site_url} = data;
if (student_id && password && database_name) {
// validating the login credential through api
}
},
signOut: async data => {
await AsyncStorage.removeItem('user_token');
dispatch({ type: 'SIGN_OUT' });
},
newSession: data => {
dispatch({ type: 'NEW_SESSION' });
},
loading: data => {
dispatch({ type: 'LOADING' });
}
});
const reducer = (state, action) => {
switch (action.type) {
case 'LOADING':
return {
...state,
isLoading: true,
newSession: false,
userToken: null
};
case 'SIGN_IN_PAGE':
return {
...state,
newSession: false,
isLoading: false,
userToken: null
};
case 'SIGN_IN_ACTION':
return {
...state,
isValidating: false,
newSession: false,
isLoading: false,
userToken: action.token,
};
case 'SIGN_OUT':
return {
...state,
newSession: true,
isLoading: false,
userToken: null,
};
case 'NEW_SESSION':
return {
...state,
newSession: true,
isLoading: false,
userToken: null
};
case 'RESTORE_TOKEN':
return {
...state,
newSession: false,
isLoading: false,
userToken: action.token
};
default:
return state;
}
};
const AuthProvider = (props) => {
const [state, dispatch] = useReducer(reducer, initialState);
const actions = createActions(dispatch);
return (
<AuthContext.Provider value={{ state, ...actions }}>
{props.children}
</AuthContext.Provider>
);
}
export default AuthProvider;
App. js
//packages
import React, { useContext } from 'react';
// third party packages
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import AsyncStorage from '@react-native-community/async-storage';
import { openDatabase } from 'react-native-sqlite-storage';
import {
createDrawerNavigator,
DrawerContentScrollView,
DrawerItemList,
DrawerItem
} from '@react-navigation/drawer';
// <----- assets and components ----->
import AuthProvider, { AuthContext } from './screens/context';
import BottomTabCotainer from './screens/tab/BottomTabContainer.js';
// drawer components
import { EditProfileScreen } from './screens/drawer/EditProfileScreen.js';
import { ChangePasswordScreen } from './screens/drawer/ChangePasswordScreen.js';
// stack components
import { OnlineClassroomScreen } from './screens/OnlineClassroomScreen.js';
import { InstituteCodeScreen } from './screens/InstituteCodeScreen.js';
import { LoginScreen } from './screens/LoginScreen.js';
import { NewSessionScreen } from './screens/NewSessionScreen.js';
import LoadingScreen from './screens/LoadingScreen.js';
// <!----- assets and components ----->
var db = openDatabase({ name: 'UserDatabase.db' });
const Drawer = createDrawerNavigator();
const Stack = createStackNavigator();
function CustomDrawerContent(props) {
const { signOut } = useContext(AuthContext);
return (
<DrawerContentScrollView {...props}>
<DrawerItemList {...props} />
<DrawerItem label="Logout" onPress={signOut} />
</DrawerContentScrollView>
);
}
export default function App() {
const { state } = useContext(AuthContext);
React.useEffect(() => {
// Fetch the token from storage then navigate to our appropriate place
const bootstrapAsync = async () => {
let userToken;
try {
userToken = await AsyncStorage.getItem('user_token');
if (userToken) {
await AsyncStorage.getItem('expire_at', async (err, value) => {
if (value !== null && new Date(value) < (new Date())) {
newSession();
} else {
dispatch({ type: 'RESTORE_TOKEN', token: userToken });
}
});
} else {
new Promise((resolve, reject) => {
// creating users table
db.transaction(function (txn) {
txn.executeSql(
"SELECT name FROM sqlite_master WHERE type='table' AND name='users'",
[],
function (tx, res) {
if (res.rows.length == 0) {
txn.executeSql(
'DROP TABLE IF EXISTS users',
[],
function(tx, res) {
console.log('table dropped');
}
);
txn.executeSql(
'CREATE TABLE IF NOT EXISTS users(id INTEGER PRIMARY KEY AUTOINCREMENT, full_name VARCHAR(100), username VARCHAR(100), password VARCHAR(100), site_url VARCHAR(100), database_name VARCHAR(50), image_location VARCHAR(100) NULL)',
[],
function(tx, res) {
console.log('table created');
resolve(res);
}
);
} else {
resolve(res);
}
}
);
});
});
db.transaction(function (txn) {
txn.executeSql(
"SELECT * from users",
[],
function(tx, res) {
if (res.rows.length > 0) {
newSession();
} else {
signInPage();
}
}
);
});
}
} catch (e) {
// Restoring token failed
}
};
bootstrapAsync();
}, []);
return (
<AuthProvider>
<NavigationContainer>
{state.isLoading ? (
<Stack.Navigator>
<Stack.Screen name="Loading" component={LoadingScreen} options={{ headerShown: false }} />
</Stack.Navigator>
) : state.newSession ? (
<Stack.Navigator>
<Stack.Screen name="NewSession" component={NewSessionScreen} options={{ headerShown: false }} />
<Stack.Screen name="InstituteCode" component={InstituteCodeScreen} options={{ headerShown: false }} />
<Stack.Screen name="Login" component={LoginScreen} options={{ headerShown: false }} />
</Stack.Navigator>
) : state.userToken == null ? (
<Stack.Navigator>
<Stack.Screen name="InstituteCode" component={InstituteCodeScreen} options={{ headerShown: false }} />
<Stack.Screen name="Login" component={LoginScreen} options={{ headerShown: false }} />
</Stack.Navigator>
) : (
<Drawer.Navigator drawerContent={(props) => <CustomDrawerContent {...props} />}>
<Drawer.Screen name="Dashboard" component={BottomTabCotainer} />
<Drawer.Screen name="Edit Profile" component={EditProfileScreen} />
<Drawer.Screen name="Change Password" component={ChangePasswordScreen} />
<Drawer.Screen name="OnlineClass" component={OnlineClassroomScreen} options={{ headerShown: false }} />
</Drawer.Navigator>
)}
</NavigationContainer>
</AuthProvider>
);
}