I'm new to programming and following this video, my code until now has had no problems, but when I try
console.log(currentUser);
It returns undefined while it shouldn't, the user is logged in and all of their information is correct in Firebase. Also, my code doesn't show any errors.
This is the code:
import React, { Component } from 'react';
import {Text, View} from 'react-native';
import firebase from 'firebase'
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { fetchUser } from '../../redux/actions/index';
export class Main extends Component {
componentDidMount() {
this.props.fetchUser();
}
render() {
const { currentUser } = this.props;
console.log(currentUser)
if (currentUser==undefined){
return(
<View></View>)
}
return (
<View style={{ flex: 1, justifyContent: 'center'}}>
<Text>User is logged in</Text>
</View>
)
}
}
const mapStateToProps = (store) => ({
currentUser: store.userState.currentUser
})
const mapDispatchProps = (dispatch) => bindActionCreators({fetchUser}, dispatch)
export default connect(null, mapDispatchProps)(Main);
And this is the parent component code:
import React, { Component } from 'react';
import { StyleSheet, Text, View } from 'react-native';
require('dotenv').config();
import firebase from 'firebase';
const firebaseConfig = {
//personal info
};
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import rootReducer from './redux/reducers';
import thunk from 'redux-thunk';
const store = createStore(rootReducer, applyMiddleware(thunk))
if(firebase.apps.length === 0){
firebase.initializeApp(firebaseConfig)
}
import {NavigationContainer} from '#react-navigation/native';
import {createStackNavigator} from '#react-navigation/stack';
import {createMaterialTopTabNavigator} from 'react-navigation-tabs';
import LandingScreen from './Components/auth/Landing';
import RegisterScreen from './Components/auth/Register';
import MainScreen from './Components/auth/Main';
const Stack = createStackNavigator();
export class App extends Component {
constructor(props) {
super(props);
this.state = {
loaded: false,
}
}
componentDidMount(){
firebase.auth().onAuthStateChanged((user) => {
if (!user){
this.setState({
loggedIn: false,
loaded: true,
})
}else{
this.setState({
loggedIn: true,
loaded: true,
})
}
})
}
render() {
const { loggedIn, loaded } = this.state
if (!loaded){
return(
<View style={{ flex: 1, justifyContent: 'center'}}>
<Text>Loading</Text>
</View>
)
}
if (!loggedIn) {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="Landing">
<Stack.Screen name="Landing" component={LandingScreen} options={{headerShown: false}}/>
<Stack.Screen name="Register" component={RegisterScreen}/>
</Stack.Navigator>
</NavigationContainer>
);
}
return(
<Provider store={store}>
<MainScreen/>
</Provider>
)
}
};
export default App
Related
I am getting this error /!\ You are using legacy implementaion. Please update your code: use createWrapper() and wrapper.useWrappedStore(). when I compile my application. The application works fine, but I do not know why I get the error. I tried configuring similar to other projects on google and nothing seems to work.
I tried using this solution, but had no luck. Not sure how to fix this.
Here is my _app.tsx
import type { AppProps } from 'next/app'
import { Toaster } from 'react-hot-toast';
import { useRouter } from 'next/router';
import { wrapper } from '../features/store';
import useAuth from '../hooks/useAuth';
import useDarkMode from '../hooks/useDarkMode';
import '../styles/global.css';
const App = ({ Component, pageProps }: AppProps) => {
useAuth();
useDarkMode();
const router = useRouter();
return (
<main>
<Component {...pageProps} key={router.asPath} />
<Toaster
position="bottom-center"
toastOptions={{
duration: 3000,
}}
/>
</main>
)
};
export default wrapper.withRedux(App);
here is index.tsx
import { useEffect } from "react";
import { useRouter } from "next/router";
import { useSelector } from "react-redux";
import { User } from "../domain/accounts/user";
import Loading from "../icons/Loading";
import useUser from "../hooks/useUser";
const Home = () => {
const user = useUser();
const router = useRouter();
useEffect(() => {
if (user.isAuthenticated !== null) {
if (user.isAuthenticated) router.push('/home');
if (!user.isAuthenticated) router.push('/explore')
}
}, [user.isAuthenticated]);
return (
<div style={{
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
minHeight: '95vh',
}}>
<Loading height={80} width={80} />
</div>
);
}
export default Home;
here is store.js
import { configureStore } from "#reduxjs/toolkit";
import { userSlice } from "./user";
import { userPreferenceSlice } from "./userPreference";
import { createWrapper } from "next-redux-wrapper";
const makeStore = () => {
return configureStore({
reducer: {
user: userSlice.reducer,
userPreference: userPreferenceSlice.reducer,
},
});
}
export const wrapper = createWrapper(makeStore);
Did you try npm install next-redux-wrapper
Then, in _app.tsx try replaceing the wrapper.withRedux import with import { useWrappedStore } from "next-redux-wrapper";
And instead of using the wrapper.withRedux function, try using the useWrappedStore method:
const MyAppWithRedux = useWrappedStore(MyApp);
export default MyAppWithRedux;
I simply want my render method code run after update state in useEffect.
I store my token in asyncStorage and now I want if token exist then it redirect at homePage else return at loginPage. But problem is that render method run before updating my state in useEffect. And it keeps me on loginPage even I had token.
My code Is below:
import React, { useEffect, useState } from 'react';
import { createStackNavigator } from '#react-navigation/stack';
import { NavigationContainer } from '#react-navigation/native';
import { StyleSheet, Text, View} from 'react-native';
import AsyncStorage from '#react-native-async-storage/async-storage';
import { useLinkProps, useNavigation, CommonActions } from '#react-navigation/native';
import MainScreen from './src/screens/MainScreen';
import SignIn from './src/screens/SignIn';
const Stack = createStackNavigator();
const App = props => {
const [isSigned, setIsSigned] = useState(false);
useEffect(async () => {
let token = await AsyncStorage.getItem("#token");
console.log("token", token);
if (token) {
setIsSigned(true);
props.navigation.navigate('MainScreen');
}
else {
setIsSigned(false);
props.navigation.navigate('SignIn');
}
}, [])
return (
<NavigationContainer>
<Stack.Navigator
initialRouteName={isSigned ? "MainScreen" : "SignIn"}
screenOptions={{
headerShown: false
}}
>
<Stack.Screen name="Login" component={SignIn} />
<Stack.Screen name="MainScreen" component={MainScreen} />
</Stack.Navigator>
</NavigationContainer>
);
};
const styles = StyleSheet.create({
container: {
marginTop: Platform.OS === 'android' ? '3%' : '10%'
}
});
export default App;
You could add another state value to conditionally render your markup:
import React, { useEffect, useState } from 'react';
import { createStackNavigator } from '#react-navigation/stack';
import { NavigationContainer } from '#react-navigation/native';
import { StyleSheet, Text, View} from 'react-native';
import AsyncStorage from '#react-native-async-storage/async-storage';
import { useLinkProps, useNavigation, CommonActions } from '#react-navigation/native';
import MainScreen from './src/screens/MainScreen';
import SignIn from './src/screens/SignIn';
const Stack = createStackNavigator();
const App = props => {
// Manage state whether component has been loaded.
const [isLoaded, setIsLoaded] = useState(false);
const [isSigned, setIsSigned] = useState(false);
useEffect(() => {
let token = await AsyncStorage.getItem("#token");
if (token) {
setIsSigned(true);
props.navigation.navigate('MainScreen');
} else {
setIsSigned(false);
props.navigation.navigate('SignIn');
}
// Tell your component it's been loaded.
setIsLoaded(true);
}, []);
// Don't render if not loaded.
if (!isLoaded) return <></>;
return (
<NavigationContainer>
<Stack.Navigator
initialRouteName={isSigned ? "MainScreen" : "SignIn"}
screenOptions={{
headerShown: false
}}
>
<Stack.Screen name="Login" component={SignIn} />
<Stack.Screen name="MainScreen" component={MainScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
TypeError: undefined is not an object (evaluating 'this.props.all_subjects.current').
Index.js
import { registerRootComponent } from 'expo';
import App from './App';
// registerRootComponent calls AppRegistry.registerComponent('main', () => App);
// It also ensures that whether you load the app in the Expo client or in a native build,
// the environment is set up appropriately
registerRootComponent(App);
App.js
import 'react-native-gesture-handler';
import React, { Component } from 'react';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import { StyleSheet } from 'react-native';
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
import subjectsReducer from './reducers/subjectsReducer';
import Home from "./screens/home";
import Subjects from "./screens/subjects";
const store = createStore(subjectsReducer);
const Stack = createStackNavigator();
class App extends Component {
render() {
return (
<Provider store={store}>
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen
name="Home"
component={Home}
/>
<Stack.Screen
name="Subjects"
component={Subjects}
/>
</Stack.Navigator>
</NavigationContainer>
</Provider>
);
}
}
export default App;
subjectsReducers.js
import { combineReducers } from 'redux';
const INITIAL_STATE = {
current: [],
all_subjects: [
'Literature',
'Speech',
'Writing',
'Algebra',
'Geometry',
'Statistics',
'Chemisrty',
'Biology',
'Physics',
'Economics',
'Geography',
'History',
],
};
const subjectsReducer = (state = INITIAL_STATE, action) => {
switch (action.type) {
case 'SELECT_SUBJECT':
// copy the state
const { current, all_subjects,} = state;
//remove a subject from the all_subjects array
const addedSubject = all_subjects.splice(action.payload, 1);
// put subject in current array
current.push(addedSubject);
// update the redux state to reflect the change
const newState = { current, all_subjects };
//return new state
return newState;
default:
return state
}
};
export default combineReducers({
subjects: subjectsReducer
});
subjectsActions.js
export const addSubject = subjectsIndex => (
{
type: 'SELECT_SUBJECT',
payload: subjectsIndex,
}
);
Subjects.js
import React from 'react';
import { connect } from 'react-redux';
import { StyleSheet, Text, View, Button } from 'react-native';
class Subjects extends React.Component {
render() {
return (
<View style={styles.container}>
<Text>Select Subjects Below!</Text>
{this.props.subjects.all_subjects.map((subject, index) => (
<Button
key={ subject }
title={ `Add ${ subject }` }
onPress={() =>
this.props.addSubject(index)
}
/>
))}
<Button
title="Back to home"
onPress={() =>
this.props.navigation.navigate('Home')
}
/>
</View>
);
}
}
// const mapStateToProps = (state) => {
// const { subjects } = state
// return { subjects }
// };
const mapStateToProps = state => ({
subjects: state.subjects
});
export default connect(mapStateToProps)(Subjects);
Home.js
import React from 'react';
import { connect } from 'react-redux';
import { StyleSheet, Text, View, Button } from 'react-native';
class Home extends React.Component {
render() {
return (
<View style={styles.container}>
<Text>You have { this.props.all_subjects.current.length } subjects.</Text>
<Button
title="Select more subjects"
onPress={() =>
this.props.navigation.navigate('Subjects')
}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
text:{
color: '#888',
fontSize: 18
},
input: {
margin: 15,
height: 40,
borderColor: '#7a42f4',
borderWidth: 1
},
submitButton: {
backgroundColor: '#7a42f4',
padding: 10,
margin: 15,
height: 40,
},
submitButtonText:{
color: 'white'
}
});
// const mapStateToProps = (state) => {
// const { subjects } = state
// return { subjects }
// };
const mapStateToProps = state => ({
subjects: state.subjects
});
export default connect(mapStateToProps, null)(Home);
I am new to react native. I have searched everywhere for a solution for this issue, but I can’t seem to get anywhere. I have used redux in standard react, but I don’t know why this isn’t working. Any thoughts or suggestions would be greatly appreciated.
I am using Redux Form to capture user info submission. I've connected Redux Form with the store and written the form according to the instructions, but when clicking the submit button, no values are passed through.
I do not usually ask on Stack Overflow so please excuse for my bad wording. I do not know how to articulate my problem.
I copied my code on to snack expo (link: https://snack.expo.io/S1_6f7dQV)
Here are my codes:
Components/Form.js
import React, { Component } from 'react';
import { Field, reduxForm } from 'redux-form';
import { StyleSheet, View, Text, TouchableOpacity, TextInput } from 'react-native';
const renderField = ({ label, keyboardType, name }) => {
return (
<View>
<Text>{label}</Text>
<TextInput keyboardType={keyboardType}
>
</TextInput>
</View>
);
};
const submit = values => {
alert(`here is the value ${JSON.stringify(values)}`)
}
const ContactComponent = props => {
const { handleSubmit } = props;
console.log('handle submit ...');
console.log(handleSubmit);
return (
<View>
<Text>Redux-form example</Text>
<Field keyboardType="default" label="Username: " component={renderField} name="Username" />
<Field keyboardType="email-address" label="Email: " component={renderField} name="Email" />
<TouchableOpacity onPress={handleSubmit(submit)} style={{ margin: 10, alignItems: 'center' }}>
<Text>Submit</Text>
</TouchableOpacity>
</View>
);
}
const ContactForm = reduxForm({
form: 'contact', // a unique identifier for this form
})(ContactComponent);
export default ContactForm;
Component/MainComponent.js
import { createStackNavigator, createAppContainer } from 'react-navigation';
import HomeScreen from '../screens/HomeScreen';
import React, { Component } from 'react';
import { View, Icon} from 'native-base';
const MainNavigator = createStackNavigator({
Home: { screen: HomeScreen }
// AddTransaction: { screen: AddTransaction },
// TransactionList: { screen: TransactionList }
})
const Main = createAppContainer(MainNavigator);
export default Main;
Screen/HomeScreen.js
import React, {Component} from 'react';
import { Container, View, Text, Content, Button, Form } from 'native-base';
import ContactForm from '../components/Form.js';
class HomeScreen extends Component {
static navigationOptions = {
title: 'Home',
}
render() {
return (
<Container>
<ContactForm/>
</Container>
);
}
}
export default HomeScreen;
App.js
import React from 'react';
import { View, Text } from 'native-base';
import Main from './components/MainComponent';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware, combineReducers } from 'redux';
import { createLogger } from 'redux-logger';
import { reducer as formReducer } from 'redux-form';
const rootReducer = combineReducers({
form: formReducer,
});
export const store = createStore(rootReducer)
export default class App extends React.Component {
render() {
return (
<Provider store={store}>
<Main />
</Provider>
);
}
}
Try including the input props to yout TextInput like below, as shown in the example here on ReduxForm's docs
const renderField = ({ label, keyboardType, name, input }) => {
return (
<View>
<Text>{label}</Text>
<TextInput keyboardType={keyboardType} {...input}
>
</TextInput>
</View>
);
};
I am trying to combine navigation, more exactly stack navigation with my react native redux application, and I encountered this error during debugging. From what I've already searched, it's because the navigation isn't really compatible with the redux mode of work. So I tried a solution to my problem, but still I have the same error. Here is my code:
Login.js
import React, { Component } from 'react';
import { View, ActivityIndicator, TouchableHighlight } from 'react-native';
import { getLogger, issueToText } from '../core/utils';
import styles from '../core/styles';
import { Card, Button, FormLabel, FormInput } from "react-native-elements";
import { connect } from 'react-redux'
import { loginAction } from '../actions/LoginActions'
class LoginComponent extends Component {
constructor(props) {
super(props);
this.login = this.login.bind(this)
}
render() {
const { error, isLoading } = this.props;
const inputFormProp = {
username: '',
password: ''
};
return (
<View style={{ paddingVertical: 20 }}>
<Card>
<FormLabel>Email</FormLabel>
<FormInput value={inputFormProp.username} onChangeText={(text) => inputFormProp.username = text} />
<FormLabel>Password</FormLabel>
<FormInput value={inputFormProp.password} onChangeText={(text) => inputFormProp.password = text} />
<Button
buttonStyle={{ marginTop: 20 }}
backgroundColor="#03A9F4"
title="SIGN IN"
onPress={this.login(inputFormProp)}
/>
</Card>
<ActivityIndicator animating={this.props.isLoading} style={styles.activityIndicator} size="large" />
</View>
);
}
login(inputFormProp) {
console.log(this.props)
const { store } = this.props.screenProps.store;
console.log(loginAction)
const { dispatch } = this.props
console.log(dispatch)
dispatch(loginAction(inputFormProp))
.then(() => {
if (this.props.error === null && this.props.isLoading === false) {
if (store.getState().auth.token) {
this.props.navigation.navigate('ProductList', { token: store.getState().auth.token });
}
}
})
.catch(error => {
});
}
}
function mapStateToProps(state) {
const { error, isLoading } = state.auth
return {
error,
isLoading,
}
}
export default connect(mapStateToProps)(LoginComponent)
App.js
import React, { Component } from 'react';
import { createStore, applyMiddleware, combineReducers, compose } from 'redux';
import { createLogger } from 'redux-logger';
import thunk from 'redux-thunk';
import { authReducer } from "./src/reducers/LoginReducer";
import { productReducer } from "./src/product/service";
import { ProductList } from "./src/product/ProductList";
import { LoginComponent } from "./src/components/Login";
import { Provider, connect } from "react-redux";
import { StackNavigator, addNavigationHelpers } from "react-navigation";
import Routes from "./src/core/routes";
const AppNavigator = StackNavigator(Routes, {
navigationOptions: {
title: ({ state }) => {
if (state.params) {
return `${state.params.title}`;
}
}
}
});
const navReducer = (state, action) => {
const newState = AppNavigator.router.getStateForAction(action, state);
return newState || state;
};
#connect(state => ({
nav: state.nav
}))
class AppWithNavigationState extends Component {
render() {
return (
<AppNavigator
navigation={addNavigationHelpers({
dispatch: this.props.dispatch,
state: this.props.nav
})}
/>
);
}
}
const initialState = {
auth: { isLoading: false, error: null },
};
const rootReducer = combineReducers({ product: productReducer, auth: authReducer, nav: navReducer });
let store = createStore(rootReducer, initialState,
compose(applyMiddleware(thunk, createLogger())));
export default function App() {
return (
<Provider store={store}>
<AppWithNavigationState />
</Provider>
);
}
Routes.js
import { ProductList } from "../product/ProductList";
import { LoginComponent } from "../components/Login";
const Routes = {
Login: { screen: LoginComponent },
ProductList: { screen: ProductList }
};
export default Routes;
Here is my error: Route Login should declare a screen.
What did I do wrong with my code? Thank you.
I fixed the error. It was because I added between LoginComponent {} in the routes.js file at:
import { LoginComponent } from "../components/Login";