I am developing a react-native application using redux. This is my app.js:
import 'react-native-gesture-handler';
import React from 'react';
import {Provider} from 'react-redux';
import AsyncStorage from '#react-native-community/async-storage';
import {DefaultTheme, Provider as PaperProvider} from 'react-native-paper';
import {NavigationContainer} from '#react-navigation/native';
import {createBottomTabNavigator} from '#react-navigation/bottom-tabs';
import Icon from 'react-native-vector-icons/Ionicons';
import AppHeader from './components/ui/AppHeader';
import Home from './views/Home';
import Login from './views/Login';
import MyCoupons from './views/MyCoupons';
import ShoppingCart from './views/ShoppingCart';
import Signup from './views/Signup';
import Intro from './views/Intro';
import reducers from './reducers/index';
import configureStore from './store';
export const store = configureStore(reducers);
const Tab = createBottomTabNavigator();
const App = () => {
let localStorageUser = null;
const getLocalStorageUser = async () => {
try {
localStorageUser = await AsyncStorage.getItem('user');
} catch (error) {
console.log(error);
}
};
const getInitialRouteName = () => {
switch(localStorageUser) {
case null: return 'Cuenta'
case '': return 'Cuenta'
default: return 'Home'
}
}
return (
<>
<AppHeader />
<Provider store={store}>
<PaperProvider>
<NavigationContainer>
<Tab.Navigator
initialRouteName={getInitialRouteName()}
screenOptions={({route}) => ({
tabBarIcon: ({focused, color, size}) => {
let iconName;
if (route.name == 'Home') {
iconName = focused? 'home': 'home-outline';
} else if (route.name == 'Mis Cupones') {
iconName = focused? 'film': 'film-outline';
} else if (route.name == 'Carrito') {
iconName = focused? 'cart': 'cart-outline';
} else if (route.name == 'Cuenta') {
iconName = focused? 'person-circle': 'person-circle-outline';
}
return <Icon name={iconName} color='blue' size={25} />
}
})}
>
<Tab.Screen name='Home' component={Home} />
<Tab.Screen name='Carrito' component={ShoppingCart} />
<Tab.Screen name='Mis Cupones' component={MyCoupons} />
<Tab.Screen name='Cuenta' component={Login}/>
</Tab.Navigator>
</NavigationContainer>
</PaperProvider>
</Provider>
</>
);
};
export default App;
This is my store/index.js:
import {applyMiddleware, compose, createStore} from 'redux';
import reducers from '../reducers/index';
import {routerMiddleware} from 'connected-react-router';
import createSagaMiddleware from 'redux-saga';
import rootSaga from '../sagas/index';
import {Provider} from 'react-redux';
import AsyncStorage from '#react-native-community/async-storage';
const sagaMiddleware = createSagaMiddleware();
const middlewares = [sagaMiddleware];
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
export default function configureStore(initialState) {
const store = createStore(initialState,
composeEnhancers(applyMiddleware(...middlewares)));
sagaMiddleware.run(rootSaga);
if (module.hot) {
// Enable Webpack hot module replacement for reducers
module.hot.accept('../reducers/index', () => {
const nextRootReducer = require('../reducers/index');
store.replaceReducer(nextRootReducer);
});
}
return store;
}
This is my reducers/index.js:
import {combineReducers} from 'redux';
import Auth from './Auth';
export default () => combineReducers({
auth: Auth,
});
This is my reducers/Auth.js:
import {
GET_USER_SUCCESS,
LOGIN_SUCCESS,
SET_USER,
} from '../types';
const INIT_STATE = {
username: null,
token: null,
userInfo: null,
};
export default (state = INIT_STATE, action) => {
switch (action.type) {
case LOGIN_SUCCESS: {
return {
...state,
username: action.payload.username,
token: action.payload.token
}
}
case GET_USER_SUCCESS: {
return {
...state,
userInfo: Object.assign({}, action.payload.userInfo)
}
}
case SET_USER: {
return {
...state,
username: null,
token: null,
userInfo: null,
}
}
default:
return state
}
}
And this is views/Login.js, where I try to connect to the store:
import React from 'react';
import {View, StyleSheet} from 'react-native';
import {Button, TextInput, Headline} from 'react-native-paper';
import globalStyles from '../styles/global';
import {connect} from 'react-redux';
import AsyncStorage from '#react-native-community/async-storage';
import {login} from '../actions/Auth';
class Login extends React.Component {
constructor (props) {
super();
this.state = {
email: '',
password: '',
loggedIn: false
};
}
render () {
const setLocalStorageUser = async (user) => {
try {
await AsyncStorage.setItem('user', user);
} catch (error) {
console.log(error);
}
};
const handleNewUserPress = () => {
navigation.navigate('Signup');
}
const handleLoginPress = async () => {
login(this.state.email, this.state.password);
navigation.navigate('Home');
}
const handleChange = (name, text) => {
this.setState({[name]: value});
}
return (
<View style={globalStyles.container}>
<TextInput style={styles.input} value={this.state.email} label="Email" onChangeText={(text) => handleChange('email', text)} />
<TextInput style={styles.input} value={this.state.password} label="Contraseña" onChangeText={(text) => handleChange('password', text)} />
<Button
style={styles.button}
mode='contained'
onPress={() => handleLoginPress()}
disabled={this.state.email=='' || this.state.password==''}
>
Enviar
</Button>
<Button color='blue' icon="plus-circle" onPress={() => handleNewUserPress()}>
Nuevo Usuario
</Button>
</View>
);
}
}
const styles = StyleSheet.create({
input: {
marginBottom: 20,
backgroundColor: 'darkgray'
},
button: {
color: 'white',
backgroundColor: 'blue',
marginBottom: 20
}
})
const mapStateToProps = ({auth}) => {
const {username, token} = auth;
return {username, token};
}
const mapDispatchToProps = {
login,
}
export default connect(mapStateToProps, mapDispatchToProps)(Login);
The problem is that this arrange is raising this exceptio:
I have checked the code several times and I haven't been able to find my mistake.
Your issue is in here:
export default () => combineReducers({
auth: Auth,
});
now your reducers you supply to createStore is a function ... not the combined-reducers
This should be
export default combineReducers({
auth: Auth,
});
Related
I'm making a ChatApp on ReactNative, on this part I'm trying to implement a SignOut function, but i don't understand what is wrong here.
enter image description here
The error is "undefined is not a function (near '...navigation.setOptions...')
The error is on the function:
useLayoutEffect(() => {
navigation.setOptions({
headerRight: () => (
<TouchableOpacity style={{ marginRight: 10 }} onPress={onSignOut}>
//<AntDesign name="logout" size={24} color={"#808080"} style={{marginRight:10}}/>
</TouchableOpacity>
)
});
}, [navigation]);
import React, {
useState,
useEffect,
useLayoutEffect,
useCallback,
} from "react";
import { TouchableOpacity, Text } from "react-native";
import { GiftedChat } from "react-native-gifted-chat";
import {
collection,
addDoc,
query,
onSnapshot
} from 'firebase/firestore';
import { signOut } from 'firebase/auth';
import { database } from "../config/firebase";
import { useNavigation } from "#react-navigation/native";
import {AntDesign} from "#expo/vector-icons";
import { Colors } from "react-native/Libraries/NewAppScreen";
import { auth } from "../config/firebase"
export default function Chat() {
const [messages, setMessages] = useState([]);
const navigation = useNavigation();
const onSignOut = () => {
signOut(auth).catch(error => console.log(error));
};
useLayoutEffect(() => {
navigation.setOptions({
headerRight: () => (
<TouchableOpacity style={{ marginRight: 10 }} onPress={onSignOut}>
//<AntDesign name="logout" size={24} color={"#808080"} style={{marginRight:10}}/>
</TouchableOpacity>
)
});
}, [navigation]);
useLayoutEffect(() => {
const collectionRef = collection(database, 'chats');
const q = query(collectionRef, orderBy('createAt', 'desc'));
const unsubscribe = onSnapshot(q, snapshot => {
console.log('snapshot');
setMessages(
snapshot.docs.map(doc => ({
_id: doc.id,
createdAt: doc.data().createdAt,
text: doc.data().text,
user: doc.data().user,
}))
)
});
return () => unsubscribe();
}, []);
const onSend = useCallback((messages = []) => {
setMessages(previousMessages => GiftedChat.append(previousMessages, messages));
const { _id, createdAt, text, user } = messages[0];
addDoc(collection(database, 'chats'), {
_id,
createdAt,
text,
user,
});
}, []);
return (
<GiftedChat
messages={messages}
onSend={messages => onSend(messages)}
user = {{
_id: auth?.currentUser?.email,
avatar: 'https://i.pravatar.cc/300'
}}
/>
);
}
The Navigation is on this part
This is the main part of the code, here i make the navigation into de login and signup part and the chat and home screens.
'''App.js Javascript
import React, {useState, createContext, useContext, useEffect} from "react";
import { NavigationContainer } from "#react-navigation/native";
import { createStackNavigator } from "#react-navigation/stack";
import { View, ActivityIndicator } from "react-native";
import { onAuthStateChanged } from "firebase/auth";
import Chat from "./src/screens/Chat";
import Login from "./src/screens/Login";
import Signup from "./src/screens/Signup";
import Home from "./src/screens/Home"
import { auth } from "./src/config/firebase";
const Stack = createStackNavigator();
const AuthenticatedUserContext = createContext({});
const AuthenticatedUserProvider = ({ children }) => {
const [user, setUser] = useState(null);
return (
<AuthenticatedUserContext.Provider value = {{user, setUser}}>
{children}
</AuthenticatedUserContext.Provider>
)
}
function AuthStack () {
return (
<Stack.Navigator defaultScreenOptions={Login} screenOptions={{headerShown: false}}>
<Stack.Screen name="Login" component={Login} />
<Stack.Screen name="Signup" component={Signup} />
</Stack.Navigator>
)
}
function ChatStack () {
<Stack.Navigator defaultScreenOptions={Home}>
<Stack.Screen name="Home" component={Home} />
<Stack.Screen name="Chat" component={Chat} />
</Stack.Navigator>
}
function RootNavigator () {
const {user, setUser} = useContext(AuthenticatedUserContext);
const [loading, setLoading] = useState(true);
useEffect(() => {
const unsubscribe = onAuthStateChanged(auth,
async authenticatedUser => {
authenticatedUser ? setUser(authenticatedUser) : setUser(null);
setLoading(false);
}
);
return () => unsubscribe();
}, [user]);
if(loading) {
return (
<View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
<ActivityIndicator size="large" />
</View>
)
}
return (
<NavigationContainer>
{ user ? <ChatStack /> : <AuthStack />}
</NavigationContainer>
)
}
export default function App(){
return (
<AuthenticatedUserProvider>
<RootNavigator />
</AuthenticatedUserProvider>
)
}
'''
I am doing an alarm app with react native. When i launch my code it gives me the following error: "could not find "store" in the context of "Connect(ListAlarms)"
Either wrap the root component in a , or pass a custom React context provider to and the corresponding React context consumer to Connect(ListAlarms) in connect options"
what am I doing wrong? what is the solution?
App.js
import React from 'react';
import {
SafeAreaView,
StyleSheet,
Text,
View,
} from 'react-native';
import DateTimePicker from '#react-native-community/datetimepicker';
import ListAlarms from './src/components/ListAlarms';
import TimePicker from './src/components/TimePicker';
const App = () => {
return (
<View style = {styles.mainContainer}>
<Text style={styles.heading}>Alarm App</Text>
<SafeAreaView style={styles.ListAlarms}>
<ListAlarms />
</SafeAreaView>
<View style={styles.TimePicker}>
<TimePicker />
</View>
</View>
);
};
const styles = StyleSheet.create({
mainContainer:{
flex:1,
alignItems: "center",
},
heading:{
fontSize:25,
padding: 20,
},
TimePicker:{
paddingTop:"10%",
width:"50%",
bottom: 20,
},
ListAlarms: {
flex: 1,
width:"100%",
}
});
export default App;
TimePicker.js
import React, { useState } from 'react';
import {
Button,
Alert
} from 'react-native';
import { connect } from 'react-redux';
import { addAlarm } from "../actions/alarms";
import DateTimePicker from 'react-native-modal-datetime-picker';
const TimePicker = (props) => {
const [isDateTimePickerVisible, setIsDateTimePickerVisible] = useState(false);
const makeid=()=>{
var length = 5;
var result = "";
var characters="0123456789";
var charactersLength=characters.length;
for (vari=0; i<length; i++){
result += characters.charAt(Math.floor(Math.random() + charactersLength));
}
return result;
}
const showDateTimePicker = () => {
setIsDateTimePickerVisible(true);
}
const hideDateTimePicker = () => {
setIsDateTimePickerVisible(false);
}
const handleDatePicker = (datetime) => {
var currentTime = Date.now();
if(datetime.getTime() < currentTime) {
Alert.alert("Please Choose future time");
hideDateTimePicker();
return;
}
const alarmNotifData={
id:makeid(),
title: "Alarms Ringing",
message: "My Notification Message",
channel: "alarm-channel",
ticker:"My Notificacion Message",
auto_canel: true,
vibrate:true,
vibration:100,
small_icon:"ic_launcher",
large_icon:"ic_launcher",
play_sound:true,
sound_name: null,
color:"red",
schedule_once:true,
tag:"some_tag",
fire_date:Date.now(),
date:{ value: datetime }
}
props.add(alarmNotifData)
hideDateTimePicker();
}
return(
<>
<Button
title = "+ Add Alarms"
color = "blue"
onPress = {() => {
showDateTimePicker();
}}
>
</Button>
<DateTimePicker
mode="datetime"
isVisible={isDateTimePickerVisible}
onConfirm={handleDatePicker}
onCancel={hideDateTimePicker}
/>
</>
);
}
const mapStateToProps= state =>{
return {};
}
const mapDispatchToProps= dispatch =>{
return {
add:alarmNotifObj=>{
dispatch(addAlarm(alarmNotifObj));
}
};
}
export default connect(mapStateToProps,mapDispatchToProps)(TimePicker);
ListAlarms.js
import React from 'react';
import {
StyleSheet,
Button,
View,
FlatList,
} from 'react-native';
import {ListItem} from 'react-native-elements';
import { connect } from 'react-redux';
import { deleteAlarm } from "../actions/alarms";
import DateTimePicker from '#react-native-community/datetimepicker';
const ListAlarms=(props)=>{
const KeyExtractor =(item,index) => index.toString();
const renderItem = ({item}) => {
return(
<ListItem>
<ListItem.Content>
<ListItem.Title style ={styles.titleStyle}>{item.time.toString()}</ListItem.Title>
<ListItem.Subtitle>{item.date.toString()}</ListItem.Subtitle>
</ListItem.Content>
<Button
title = "Remove"
color = "red"
onPress = {() => {
props.delete(item.value);
}}
>
</Button>
</ListItem>
);
}
return (
<FlatList>
KeyExtracto={KeyExtractor}
data={props.alarms}
renderItem={renderItem}
</FlatList>
);
}
const styles = StyleSheet.create({
titleStyle: { fontWeight: "bold", fontSize: 30 }
})
const mapStateToProps= state =>{
return {
alarms:state.alarms.alarms,
};
}
const mapDispatchToProps= dispatch =>{
return {
delete:value=>{
dispatch(deleteAlarm(value));
}
};
}
export default connect(mapStateToProps,mapDispatchToProps)(ListAlarms);
index.js
import { AppRegistry } from "react-native";
import App from './app.json';
import { name as appName } from './app.json';
import { Provider } from 'react-redux';
import React from 'react';
import configureStore from "./src/store";
const store = configureStore();
const RNRedux=()=>{
return <Provider store={store}>
<App />
</Provider>
}
AppRegistry.registerComponent(appName, () => RNRedux);
**index.js (in store folder)**
import { createStore, combineReducers} from 'redux';
import alarmReducer from '../reducers/alarmReducer';
const rootReducer = combineReducers({
alarms: alarmReducer,
});
const configureStore=()=>{
return createStore(rootReducer);
};
export default configureStore;
I am trying to use the values/functions from my context but every time I console.log a value that Coes from context the value is undefined.
This is my Context:
import { NativeStackNavigationProp } from '#react-navigation/native-stack';
import React, {createContext, FC, useEffect } from 'react';
import { useState } from 'react';
import {fbInit, setNewUserFireStore, subscribeUserFS } from '../services/FirebaseServices';
const initialState = {
signedIn: false,
}
export const FirebaseContext = createContext();
export const FirebaseContextProvider = ({children}) => {
const [isUserSignedIn, setIsUserSignedIn] = useState(initialState.signedIn);
useEffect(() => {
fbInit();
})
const testLog = () => {
console.log("TAG Test Log Func")
}
return (
<FirebaseContext.Provider value={{isUserSignedIn, setIsUserSignedIn}}>
{children}
</FirebaseContext.Provider>
);
}
This is where I am trying to use the values (I am trying to log the values when I press the Button)
import { useNavigation } from '#react-navigation/native';
import { StatusBar } from 'expo-status-bar';
import { StyleSheet, Text, View } from 'react-native';
import {Button, Card, TextInput} from 'react-native-paper';
import { FirebaseContext } from '../../context/FirebaseContext';
import React, {useContext, useEffect, useState } from 'react';
const initialUserState = {
userName: 'Nicole Lopez',
password: '1001008888',
}
export default function LoginScreen() {
const [disabled, setDisabled] = useState(false);
const [userState, setUserState] = useState(initialUserState);
const { fbContext } = useContext(FirebaseContext);
const navigation = useNavigation();
const onInputChange = (field, value) => {
setUserState({
...userState,
[field]: value
})
}
useEffect(() => {
setDisabled(userState.userName.length === 0 || userState.password.length === 0);
}, [userState.userName, userState.password])
return (
<View style={styles.container}>
<Card style={styles.card}>
<TextInput
mode="outlined"
label="Förnamn & Efternman"
defaultValue={userState.userName}
onChangeText={text => onInputChange("username", text)}
right={<TextInput.Icon name="account" onPress={() => {
}}/>}
style={styles.textInput}/>
<TextInput
mode="outlined"
label="Anställningsnummer 100100xxxx"
defaultValue={userState.password}
right={<TextInput.Icon name="lock"/>}
onChangeText={text => onInputChange("password", text)}
style={styles.textInput}/>
</Card>
<View style={styles.buttonRow}>
<Button
color={disabled ? "gray" : undefined}
disabled={disabled}
mode={'contained'}
icon={'login'}
onPress={() => {
console.log("TAG isUserSignedIn: " + fbContext?.isuserSignedIn)
//fbContext?.testLog()
//console.log("TAG LOGIN BTN PRESSED")
//navigation.navigate('HomeScreen')
}}>Login</Button>
</View>
</View>
);
}
This is my App.js:
import { StatusBar } from 'expo-status-bar';
import { StyleSheet, Text, View } from 'react-native';
import { createNativeStackNavigator } from '#react-navigation/native-stack';
import {StackScreens} from './src/helpers/types';
import { NavigationContainer, useNavigationContainerRef } from '#react-navigation/native';
import LoginScreen from './src/screens/LoginScreen/LoginScreen';
import HomeScreen from './src/screens/HomeScreen/HomeScreen';
import {doc, getFirestore, onSnapshot, setDoc, Unsubscribe as UnsubscribeFS} from 'firebase/firestore';
import { FirebaseContextProvider, FirebaseContext } from './src/context/FirebaseContext';
import { useContext } from 'react';
//import { navigationRef } from './RootNavigation';
//const userDocument = firestore().collection("users").doc('Cstl3bA9xwwH3UwHZJhA').get();
const Stack = createNativeStackNavigator();
export default function App() {
return (
<FirebaseContextProvider>
<Content />
</FirebaseContextProvider>
);
}
export const Content = () => {
const navigationRef = useNavigationContainerRef();
const firebaseContext = useContext({FirebaseContext});
return (
<NavigationContainer ref={navigationRef}>
<Stack.Navigator initialRouteName="LoginScreen">
<Stack.Screen name="LoginScreen" component={LoginScreen} />
<Stack.Screen name="HomeScreen" component={HomeScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
Don't know what I have missed, I have installed the packages, I have tried to log different values but all seem to be undefined :/
I believe it is undefined because you're trying to destructure the context value, maybe
const { fbContext } = useContext(FirebaseContext);
should be
const fbContext = useContext(FirebaseContext);
For someone getting undefined from context, check on which level you placed your context provider. If you want to use context in a component you should wrap this component in a context provider outside of this component!
Incorrect way
const Component = () => {
const { value1, value2 } = useContext(MyContext); //here context value will be undefined
return (
<ContextProvider>
//Component content
</ContextProvider>
)
}
Correct way
const ComponentA = () => {
const { value1, value2 } = useContext(MyContext);
return(//Component A content)
}
const ComponentB = () => {
return(
<ContextProvider>
<ComponentA/>
</ContextProvider>
)
}
I have context set up within my app. not at the root and for some reason it returns undefined.
I have this as the index where I create the context:
import React, { createContext, useContext, useReducer } from 'react'
type Action = { type: 'next' } | { type: 'back' }
type Dispatch = (action: Action) => void
type State = { step: number }
type StepProviderProps = { children: React.ReactNode }
const StepContext = createContext<{ state: State; dispatch: Dispatch } | undefined>(undefined)
const stepReducer = (state: State, action: Action) => {
switch (action.type) {
case 'next': {
return { step: state.step + 1 }
}
case 'back': {
return { step: state.step - 1 }
}
default: {
throw new Error(`Unhandled action type`)
}
}
}
const StepProvider = ({ children }: StepProviderProps) => {
const [state, dispatch] = useReducer(stepReducer, { step: 0 })
const value = { state, dispatch }
return <StepContext.Provider value={value}>{children}</StepContext.Provider>
}
const useStep = () => {
const context = useContext(StepContext)
if (context === undefined) {
throw new Error('useStep should be used within StepProvider')
} else {
return context
}
}
export { StepProvider, useStep }
then I import it here:
import { BodyText, H3, H5, H4 } from '../../typography'
import * as React from 'react'
import { Box, Icon } from '../../components'
import { useState } from 'react'
import { StyleSheet, TouchableOpacity, View } from 'react-native'
import { useNavigation } from '#react-navigation/native'
import { useAuthContext } from '../../context/AuthProvider'
import { Enum_Userspermissionsuser_Userrole } from '../../generated/graphql'
import Start from './Start'
import stepOne from './StepOne'
import { StepProvider, useStep } from './StepContext'
const OnboardingScreen = () => {
const [stepper, setStepper] = useState([0, 1, 2, 3, 4, 5])
const { navigate } = useNavigation()
const { user } = useAuthContext()
const {state:{step}} = useStep()
return (
<StepProvider>
<Container px={5} justifyContent="flex-start" downbg hasNavbar={false}>
<View style={{ flexDirection: 'row', justifyContent: 'space-evenly', marginTop:'12%'}}>
{stepper.map((step, i) => (
<Box height={5} width={50} bg="b2gpeach" borderRadius={11} key={i} />
))}
</View>
<Start />
{console.log(step)}
</Container>
</StepProvider>
)
}
export default OnboardingScreen
I think I should be able to get console log of the context but I get the context undefined error I set to check if context is defined.
You are calling useStep at the same level as the StepProvider.
You can't use the value from the context in the same component where you've wrapped it.
You need to wrap StepProvider in the parent component then use it:
import { StepProvider} from './StepContext'
const ParenComponent = () => {
<StepProvider>
<OnboardingScreen/>
</StepProvider>
}
import { BodyText, H3, H5, H4 } from '../../typography'
import * as React from 'react'
import { Box, Icon } from '../../components'
import { useState } from 'react'
import { StyleSheet, TouchableOpacity, View } from 'react-native'
import { useNavigation } from '#react-navigation/native'
import { useAuthContext } from '../../context/AuthProvider'
import { Enum_Userspermissionsuser_Userrole } from '../../generated/graphql'
import Start from './Start'
import stepOne from './StepOne'
import { useStep } from './StepContext'
const OnboardingScreen = () => {
const [stepper, setStepper] = useState([0, 1, 2, 3, 4, 5])
const { navigate } = useNavigation()
const { user } = useAuthContext()
const {state:{step}} = useStep()
return (
<Container px={5} justifyContent="flex-start" downbg hasNavbar={false}>
<View style={{ flexDirection: 'row', justifyContent: 'space-evenly', marginTop:'12%'}}>
{stepper.map((step, i) => (
<Box height={5} width={50} bg="b2gpeach" borderRadius={11} key={i} />
))}
</View>
<Start />
{console.log(step)}
</Container>
)
}
export default OnboardingScreen
You must use useContext within components wrapped with provider:
<StepProvider>
<OnboardingScreen />
</StepProvider>
So, you could do something like this:
import { BodyText, H3, H5, H4 } from '../../typography'
import * as React from 'react'
import { Box, Icon } from '../../components'
import { useState } from 'react'
import { StyleSheet, TouchableOpacity, View } from 'react-native'
import { useNavigation } from '#react-navigation/native'
import { useAuthContext } from '../../context/AuthProvider'
import { Enum_Userspermissionsuser_Userrole } from '../../generated/graphql'
import Start from './Start'
import stepOne from './StepOne'
import { StepProvider, useStep } from './StepContext'
const OnboardingScreen = () => {
const [stepper, setStepper] = useState([0, 1, 2, 3, 4, 5])
const { navigate } = useNavigation()
const { user } = useAuthContext()
const {state:{step}} = useStep()
// Provider removed
return (
<Container px={5} justifyContent="flex-start" downbg hasNavbar={false}>
<View style={{ flexDirection: 'row', justifyContent: 'space-evenly', marginTop:'12%'}}>
{stepper.map((step, i) => (
<Box height={5} width={50} bg="b2gpeach" borderRadius={11} key={i} />
))}
</View>
<Start />
{console.log(step)}
</Container>
)
}
// Export wrapped with provider
export default () => (
<StepProvider>
<OnboardingScreen />
</StepProvider>
)
what worked for me was declaring the types. Make use of the following logic:
My AuthContext.tsx
...
1. interface contextValueTypes {
login: Function,
logout: Function,
isLoading: boolean,
userToken: string,
}
2. export const AuthContext = createContext<contextValueTypes>({
login: Function,
logout: Function,
isLoading: false,
userToken: "",
});
...
And in my App.js
const App = () => {
const { isLoading, userToken } = useContext(AuthContext);
return (
<AuthProvider>
{userToken == null ? <AppStack /> : <AuthStack />}
</AuthProvider>
);
}
I hope this helps ya
FoodList.js
import React, { Component } from "react";
import { View, Text, FlatList } from "react-native";
import { Content, List, ListItem } from "native-base";
import { useSelector, useDispatch } from "react-redux";
import { deleteFood } from "../../redux/actions/food";
const FoodList = () => {
const dispatch = useDispatch();
const deleteCurrent = (key) => dispatch(deleteFood(key));
const foods = useSelector((state) => state.foodReducer.FoodList); <------------
return (
<FlatList
data={foods}
keyExtractor={(item, index) => item.key.toString()}
renderItem={(data) => <ListItem title={data.item.name} />}
/>
);
};
export default FoodList;
FoodCreate.js
import { useDispatch } from "react-redux";
import { addFood } from "../../redux/actions/food";
const FoodCreate = ({ navigation: { goBack } }) => {
const [food, setFood] = useState("");
const dispatch = useDispatch();
const submitFood = (food) => dispatch(addFodd(food));
return (
<Container>
<Header>
<Left>
<Button transparent>
<Icon
name="arrow-back"
onPress={() => this.props.navigation.goBack()}
style={{ fontSize: 25, color: "red" }}
/>
</Button>
</Left>
<Body>
<Title>Add Food</Title>
</Body>
<Right>
<Button transparent>
<Icon
name="checkmark"
style={{ fontSize: 25, color: "red" }}
onPress={() => {
submitFood(food);
setFood("");
}}
/>
</Button>
</Right>
</Header>
<View style={{ alignItems: "center", top: hp("3%") }}>
<TextInput
placeholder="Food Name"
placeholderTextColor="white"
style={styles.inptFood}
value={food}
onChangeText={(food) => setFood(food)}
/>
</View>
actions/food.js
import { ADD_FOOD, DELETE_FOOD } from "./types";
export const addFood = (food) => ({
type: ADD_FOOD,
data: food,
});
export const deleteFood = (key) => ({
type: DELETE_FOOD,
key: key,
});
store/store.js
import { createStore, combineReducers } from "redux";
import foodReducer from "../reducers/foodReducer";
const rootReducer = combineReducers({
foodReducer: foodReducer,
});
const configureStore = () => createStore(rootReducer);
export default configureStore;
actions/types.js
export const ADD_FOOD = "ADD_FOOD";
export const DELETE_FOOD = "DELETE_FOOD";
reducers/foodReducer.js
import { ADD_FOOD, DELETE_FOOD } from "../actions/types";
const initialState = {
FoodList: [],
};
const foodReducer = (state = initialState, action) => {
switch (action.type) {
case ADD_FOOD:
return {
...state,
FoodList: state.FoodList.concat({
key: Math.random(),
name: action.data,
}),
};
case DELETE_FOOD:
return {
...state,
FoodList: state.FoodList.filter((item) => item.key != action.key),
};
default:
return state;
}
};
export default foodReducer;
App.js
import FoodListScreen from "./components/Main/FoodList.js";
import configureStore from "./redux/store/store";
const Stack = createStackNavigator();
const Tab = createBottomTabNavigator();
const store =
(createStore(rootReducer, applyMiddleware(thunk)), configureStore());
return (
<Provider store={store}>
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen
name="FoodCreate"
component={FoodCreateScreen}
options={{ headerShown: false }}
/>
<Stack.Screen
name="FoodList"
component={FoodListScreen}
options={{ headerShown: false }}
/>
</Stack.Navigator>
</NavigationContainer>
</Provider>
Hey everyone, I'm new to redux and I'm trying to use it my Diet App, the user creates a Food item in FoodCreate.js and it will be listed in FoodList.js, at the moment when I run the code it gives me back the following error: state.foodReducer.FoodList is undefined, I put an arrow next to the line of code that gives me the error, I used this approach by following the following YouTube tutorial: https://www.youtube.com/watch?v=jTJ6zo5GO7E, thank in advance for your help.
ok maybe i found
//In your store/store.js
import { createStore, combineReducers,applyMiddleware } from "redux";
import thunk from 'redux-thunk'
import foodReducer from "../reducers/foodReducer";
const configureStore = () => {
const store = createStore(
combineReducers({
foodReducer: foodReducer,
}),
applyMiddleware(thunk)
);
return store;
}
export default configureStore;
//In your App.js
...
import configureStore from "./redux/store/store";
const store = ConfigureStore();
return(
<Provider store={store}>
...
</Provider>
)