Can't change variable when using Firebase onAuthStateChanged - firebase

I'm writing an app in React Native and I'm trying to make the app change screen automatically depending on if the user is logged in or not.
Everything works except that the variable isSignedIn is undefined so what I need help with is how to define it inside onAuthStateChanged.
Thankful for help!
Here is my code:
import { StatusBar } from 'expo-status-bar';
import { StyleSheet, Text, View } from 'react-native';
import React, { useEffect, useState } from 'react';
import { NavigationContainer, useNavigation } from '#react-navigation/native';
import { createNativeStackNavigator } from '#react-navigation/native-stack';
import { createMaterialBottomTabNavigator } from '#react-navigation/material-bottom-tabs';
import { useFonts } from 'expo-font';
import { getAuth, onAuthStateChanged } from "firebase/auth";
import { auth } from './app/config/firebase';
import IntroSliderScreen from './app/screens/introSlider';
import FirstScreenScreen from './app/screens/firstScreen';
import LogInScreen from './app/screens/logIn';
import OverrideScreen from './app/screens/override';
import SignUpScreen from './app/screens/signUp';
import HomeScreen from './app/screens/mainTabs/home';
import KartaScreen from './app/screens/mainTabs/karta';
import MatScreen from './app/screens/mainTabs/mat';
import MoreScreen from './app/screens/mainTabs/more';
import ProgramScreen from './app/screens/mainTabs/program';
import Push from './app/config/push';
const Stack = createNativeStackNavigator();
const Tab = createMaterialBottomTabNavigator ();
function MainTabs() {
return(
<Tab.Navigator>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Program" component={ProgramScreen} />
<Tab.Screen name="Karta" component={KartaScreen} />
<Tab.Screen name="Mat" component={MatScreen} />
<Tab.Screen name="More" component={MoreScreen} />
</Tab.Navigator>
);
}
export default function App() {
const [loaded] = useFonts({
PirataOne: require('./app/assets/fonts/PirataOne-Regular.ttf'),
RobotoMono: require('./app/assets/fonts/RobotoMono-VariableFont_wght.ttf'),
});
if (!loaded) {
return null;
};
var isSignedIn;
//const [isSignedIn, setIsSignedIn] = useState(false);
onAuthStateChanged(auth, (user) => {
if (user) {
// User is signed in
// https://firebase.google.com/docs/reference/js/firebase.User
const uid = user.uid;
// ...
console.log('Inloggad med UserID: ' + uid);
//setIsSignedIn(true);
} else {
// User is signed out
// ...
console.log('Ej inloggad');
}
});
return (
<NavigationContainer>
{isSignedIn ? (
<Stack.Navigator>
<Stack.Screen name='MainTabs' component={MainTabs} />
<Stack.Screen name="IntroSliderScreen" component={IntroSliderScreen} />
</Stack.Navigator>
) : (
<Stack.Navigator>
<Stack.Screen options={{headerShown: false}} name="FirstScreenScreen" component={FirstScreenScreen} />
<Stack.Screen name="SignUpScreen" component={SignUpScreen} />
<Stack.Screen name="LogInScreen" component={LogInScreen} />
</Stack.Navigator>
)}
</NavigationContainer>
);
}
/* <Stack.Group navigationKey={isSignedIn ? 'user' : 'guest'}>
<Stack.Screen name="OverrideScreen" component={OverrideScreen} />
<Stack.Screen name="Push" component={Push} />
</Stack.Group> */

Related

Navigate from HomeScreen to other screen react-native

I'm very new in RN and i was making simple app and got this error:
The action 'NAVIGATE' with payload {"name":"LoginScreen"} was not handled by any navigator.
Do you have a screen named 'LoginScreen'?
If you're trying to navigate to a screen in a nested navigator, see https://reactnavigation.org/docs/nesting-navigators#navigating-to-a-screen-in-a-nested-navigator.
My App.js:
import { StatusBar } from 'expo-status-bar';
import React from 'react'
import { StyleSheet, Text, View } from 'react-native';
import { NavigationContainer } from '#react-navigation/native';
import { createNativeStackNavigator } from '#react-navigation/native-stack';
import LoginScreen from './screens/LoginScreen'
import HomeScreen from './screens/HomeScreen'
const Stack = createNativeStackNavigator();
export default function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen options={{headerShown: false}} name="Login" component={LoginScreen} />
<Stack.Screen name="Home" component={HomeScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
HomeScreen.js:
import { StackActions, useNavigation } from '#react-navigation/core'
import React from 'react'
import { StyleSheet, Text, TouchableOpacity, View, Button, SafeAreaView } from 'react-native'
import { auth } from '../firebase'
import { NavigationContainer } from '#react-navigation/native';
import { createNativeStackNavigator } from '#react-navigation/native-stack';
import AuditScreen from './AuditScreen';
import ReportAuditScreen from './ReportAuditScreen';
import LoginScreen from './LoginScreen';
const HomeScreen = () => {
const navigation = useNavigation()
const Stack = createNativeStackNavigator()
const handleSignOut = () => {
auth
.signOut()
.then(() => {
navigation.replace("Login")
})
.catch(error => alert(error.message))
}
return (
<SafeAreaView>
<View>
<Text>Siema Home</Text>
<Button title="Out" onPress={handleSignOut}/>
<Button title="Audit" onPress={() => navigation.navigate("AuditScreen")}/>
</View>
</SafeAreaView>
)
}
I want to go to AuditScreen after click Audit button.

'NAVIGATE' with payload {"name":"LoginStack","params":{"screen":"Login"}} was not handled by any navigator

I have an error when navigating from Home to Login Screen when the user press the button Sign out.
Here is the App component:
import { NavigationContainer } from "#react-navigation/native";
import { createNativeStackNavigator } from "#react-navigation/native-stack";
import { LoginScreen } from "./Screens/LoginScreen";
import { HomeScreen } from "./Screens/HomeScreen";
import { SignUpScreen } from "./Screens/SignUpScreen";
import { CardScreen } from "./Screens/CardScreen";
import { useEffect, useState } from "react";
import { auth } from "./firebase/firebase";
const Stack = createNativeStackNavigator();
export default function App() {
const [user, setUser] = useState(null);
useEffect(() => {
auth.onAuthStateChanged((user) => {
if (user !== null) setUser(user);
});
}, []);
const LoginStack = () => {
return (
<>
<Stack.Screen
name="Login"
component={LoginScreen}
options={{ headerShown: false }}
/>
<Stack.Screen
name="SignUp"
component={SignUpScreen}
options={{ headerShown: false }}
/>
</>
);
};
return (
<NavigationContainer>
<Stack.Navigator>
{user ? (
<>
<Stack.Screen
name="Home"
component={HomeScreen}
options={{ headerShown: false }}
/>
<Stack.Screen name="CardScreen" component={CardScreen} />
</>
) : (
<Stack.Screen name="LoginStack" component={LoginStack} />
)}
</Stack.Navigator>
</NavigationContainer>
);
}
Here is the Home component:
import { MaterialCommunityIcons } from "#expo/vector-icons";
import { createBottomTabNavigator } from "#react-navigation/bottom-tabs";
import { signOut } from "firebase/auth";
import { Button } from "react-native";
import { auth } from "../firebase/firebase";
import { DashboardScreen } from "./DashboardScreen";
import { SettingsScreen } from "./SettingsScreen";
const Tab = createBottomTabNavigator();
const HomeScreen = ({ navigation }) => {
const handleSignout = () => {
signOut(auth)
.then(() => {
console.log("Sign out");
navigation.navigate("LoginStack", { screen: "Login" });
})
.catch((error) => {
console.log("Error", error);
});
};
return (
<Tab.Navigator
screenOptions={({ route }) => ({
tabBarIcon: ({ focused, color, size }) => {
let iconName;
if (route.name === "Dashboard") {
iconName = focused ? "pin" : "pin-outline";
} else if (route.name === "Settings") {
iconName = focused ? "account-circle" : "account-circle-outline";
}
// You can return any component that you like here!
return (
<MaterialCommunityIcons name={iconName} size={size} color={color} />
);
},
tabBarActiveTintColor: "#95E0B6",
tabBarInactiveTintColor: "gray",
})}
>
<Tab.Screen
name="Dashboard"
component={DashboardScreen}
options={{ headerShown: false }}
/>
<Tab.Screen
name="Settings"
component={SettingsScreen}
options={{
headerRight: () => (
<Button onPress={handleSignout} title="Sign out" />
),
}}
/>
</Tab.Navigator>
);
};
export { HomeScreen };
I'm following the instructions described here related to the nested navigator but seems to not work: https://reactnavigation.org/docs/nesting-navigators/#navigating-to-a-screen-in-a-nested-navigator
Any idea about how can I navigate from the Home Screen to the Login Screen?
Thanks
Your screen stack constructor depends on user variable.
You can't navigate to a stack that is not built, but you can set the user = null and the application will render automatically to LoginStack.
The best practice to manage user signIn/signOut is to put the user state in a context.

react-transition-group not work until reload the page

I made an simple taskshceduler with react router 5 and react redux and work fine still.
Now I try animating between different route with react-transition-group.
If I click the url changed BUT the screen not re-render until i reload the page mannualy.
Th animation only works when i use the backward button on the browser
I not get error to the console.
What is the problem and What is the solution?
Thank you
App.js
import { Fragment, useEffect, Suspense } from "react";
import { useSelector, useDispatch } from "react-redux";
import Notification from "./shared/UIElements/Notification";
import { sendCartData, fetchCartData } from "./store/cart-actions";
import Auth from "./Auth/page/Auth";
import TaskMain from "./tasks/page/TaskMain";
import TaskFilter from "./tasks/page/TaskFilter";
import MainNavigation from "./Layout/Navigation/MainNavigation";
import LoadingSpinner from "./shared/UIElements/LoadingSpinner";
import TransitionGroup from "react-transition-group/TransitionGroup";
import CSSTransition from "react-transition-group/CSSTransition";
import "../src/scss/styles.css";
import UpdateTask from "./tasks/page/UpdateTask";
import {
BrowserRouter as Router,
Route,
Redirect,
Switch,
useLocation,
} from "react-router-dom";
import NewTask from "./tasks/page/NewTask";
let isInitial = true;
function App() {
const dispatch = useDispatch();
const cart = useSelector((state) => state.cart);
const notification = useSelector((state) => state.ui.notification);
const logged = useSelector((state) => state.cart.logged);
const location = useLocation();
useEffect(() => {
dispatch(fetchCartData());
console.log(`fetch usefeect`);
}, [dispatch]);
useEffect(() => {
if (isInitial) {
isInitial = false;
return;
}
if (cart.changed) {
dispatch(sendCartData(cart));
}
}, [cart, dispatch]);
let routes;
if (!logged) {
routes = (
<Switch location={location}>
<Route path="/" exact>
<Auth />
</Route>
<Redirect to="/" />
</Switch>
);
} else {
routes = (
<Switch location={location}>
<Route path="/" exact>
<TaskMain />
</Route>
<Route path="/tasks/new" exact>
<NewTask />
</Route>
<Route path="/tasks/update/:id" exact>
<UpdateTask />
</Route>
<Route path="/items" exact>
<TaskFilter />
</Route>
<Redirect to="/" />
</Switch>
);
}
return (
<Router>
<Fragment>
{notification && (
<Notification
status={notification.status}
title={notification.title}
message={notification.message}
/>
)}
<MainNavigation />
<TransitionGroup>
<CSSTransition
timeout={1250}
classNames='fade'
key={location.key}
>
<Suspense
fallback={
<div className="center">
<LoadingSpinner></LoadingSpinner>
</div>
}
>
{routes}
</Suspense>
</CSSTransition>
</TransitionGroup>
</Fragment>
</Router>
);
}
export default App;
App.css
.fade-enter {
opacity: 0;
z-index: 1;
}
.fade-enter.fade-enter-active {
transition: opacity 1250ms ease-in;
opacity: 0;
}
MainNavigation.js
import React, { useState } from 'react';
import NavLinks from './NavLinks';
import SideDrawer from './SideDrawer';
import Backdrop from '../UIElements/Backdrop';
const MainNavigation = (props) => {
const [drawerIsOpen, setDrawerIsOpen] = useState(false);
const openDrawerHandler = () => {
setDrawerIsOpen(true);
};
const closeDrawerHandler = () => {
setDrawerIsOpen(false);
};
return (
<React.Fragment>
{drawerIsOpen && <Backdrop onClick={closeDrawerHandler} />}
<SideDrawer show={drawerIsOpen} onClick={closeDrawerHandler}>
<nav className="main-navigation__drawer-nav">
<NavLinks />
</nav>
</SideDrawer>
<header className="main-header header-grid">
<button
className="main-navigation__menu-btn"
onClick={openDrawerHandler}
>
<span />
<span />
<span />
</button>
<div className="title-grid">
<h1 className="main-navigation__title fontsize-18">TODO APP</h1>
</div>
<div className="links-grid">
<NavLinks />
</div>
</header>
</React.Fragment>
);
};
export default MainNavigation;
NavLink.js
import React from "react";
import { useSelector, useDispatch } from "react-redux";
import {useHistory } from "react-router-dom";
import { cartActions } from "../../store/cart-slice";
const NavLinks = (props) => {
const logged = useSelector((state) => state.cart.logged);
const history = useHistory();
const dispatch = useDispatch();
const foOldalHandler = () => {
history.push(`/`);
};
const szuresHandler = () => {
history.push(`/items`);
};
const logoutHanler = () => {
dispatch(cartActions.logout());
};
return (
<React.Fragment>
<div>
<nav className="nav-links">
<button className="nav-links-button" onClick={foOldalHandler}>Főoldal</button>
{logged && <button className="nav-links-button" onClick={szuresHandler}>Szűrés</button>}
{logged && <button className="nav-links-button" onClick={logoutHanler}>Kijelentkezés</button>}
</nav>
</div>
</React.Fragment>
);
};
export default NavLinks;
SideDrawer.js
import React from 'react';
import ReactDOM from 'react-dom';
import { CSSTransition } from 'react-transition-group';
const SideDrawer = props => {
const content = (
<CSSTransition
in={props.show}
timeout={200}
classNames="slide-in-left"
mountOnEnter
unmountOnExit
>
<aside className="side-drawer" onClick={props.onClick}>{props.children}</aside>
</CSSTransition>
);
return ReactDOM.createPortal(content, document.getElementById('drawer-hook'));
};
export default SideDrawer;
index.js
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import store from './store/index';
import './index.css';
import App from './App';
import {
BrowserRouter,
BrowserRouter as Router,
} from "react-router-dom";
ReactDOM.render(
<Provider store={store}>
<BrowserRouter>
<App />
</BrowserRouter>
</Provider>,
document.getElementById('root')
);
NewTask.js
import React, { useState } from "react";
import { useHistory } from "react-router-dom";
import { useSelector, useDispatch } from "react-redux";
import { cartActions } from "../../store/cart-slice";
import { v4 as uuid } from "uuid";
export default function NewTask() {
const dispatch = useDispatch();
const username = useSelector((state) => state.cart.username);
const [title, setTitle] = useState("");
const [description, setDescription] = useState("");
const [status, setStatus] = useState("aktiv");
const history = useHistory();
const usernameChangeHandler = (event) => {
setTitle(event.target.value);
};
const descriptionChangeHandler = (event) => {
setDescription(event.target.value);
};
const statusChangeHandler = (event) => {
setStatus(event.target.value);
};
const newTaskHandler = (event) => {
event.preventDefault();
console.log(`title: ${title} description ${description} status: ${status}`);
dispatch(
cartActions.addTask({
id: uuid(),
username,
title,
description,
status,
})
);
history.push("/");
};
return (
<div>
<div className='main-introduction'>
<h2 >Hello {username}!</h2>
<h1>Milyen feladatot szeretnél elvégezni?</h1>
</div>
<form onSubmit={newTaskHandler}>
<label htmlFor="title">A feladat címe</label>
<br></br>
<input
id="title"
type="text"
value={title}
onChange={usernameChangeHandler}
className='input-width'
required
/>
<br></br>
<label htmlFor="description">A feladat leírása:</label>
<br></br>
<input
id="description"
type="text"
value={description}
onChange={descriptionChangeHandler}
className='input-width'
required
/>
<br></br>
<label htmlFor="status">A feladat állapotta:</label>
<br></br>
<div onChange={statusChangeHandler}>
<input type="radio" value="aktiv" name="status" required /> Aktív
<input type="radio" value="kesz" name="status" /> Teljesített
</div>
<br></br>
<button type="submit">Hozzáad</button>
</form>
</div>
);
}
package.json
"dependencies": {
"#reduxjs/toolkit": "^1.5.0",
"#testing-library/jest-dom": "^5.11.6",
"#testing-library/react": "^11.2.2",
"#testing-library/user-event": "^12.5.0",
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-redux": "^7.2.2",
"react-router-dom": "5.3.0",
"react-scripts": "4.0.1",
"react-spring": "^9.4.3",
"react-transition-group": "^4.4.2",
"use-sound": "^4.0.1",
"uuidv4": "^6.2.12",
"web-vitals": "^0.2.4"
},
I think found the answer. with help for Drew Reese
Organize my route components different file.
It cause the right rendering.
Besides that using location.pathname instead location.key.
If you have better solution please write here
Thank you
App.js
import {
Fragment,
useEffect,
Suspense,
} from "react";
import { useSelector, useDispatch } from "react-redux";
import Notification from "./shared/UIElements/Notification";
import { sendCartData, fetchCartData } from "./store/cart-actions";
import MainNavigation from "./Layout/Navigation/MainNavigation";
import LoadingSpinner from "./shared/UIElements/LoadingSpinner";
import TransitionGroup from "react-transition-group/TransitionGroup";
import CSSTransition from "react-transition-group/CSSTransition";
import "../src/scss/styles.css";
import {
BrowserRouter as Router,
useLocation,
} from "react-router-dom";
import AuthenticationApp from "./AuthenticationApp";
import TaskApp from "./TaskApp";
let isInitial = true;
function App() {
const dispatch = useDispatch();
const cart = useSelector((state) => state.cart);
const notification = useSelector((state) => state.ui.notification);
const logged = useSelector((state) => state.cart.logged);
const location = useLocation();
useEffect(() => {
dispatch(fetchCartData());
console.log(`fetch usefeect`);
}, [dispatch]);
useEffect(() => {
if (isInitial) {
isInitial = false;
return;
}
if (cart.changed) {
dispatch(sendCartData(cart));
}
}, [cart, dispatch]);
return (
<Router>
<Fragment>
{notification && (
<Notification
status={notification.status}
title={notification.title}
message={notification.message}
/>
)}
<MainNavigation />
<TransitionGroup>
<CSSTransition
timeout={1250}
classNames="fade"
pathname={location.pathname}
>
<Suspense
fallback={
<div className="center">
<LoadingSpinner></LoadingSpinner>
</div>
}
>
{!logged && <AuthenticationApp />}
{logged && <TaskApp />}
</Suspense>
</CSSTransition>
</TransitionGroup>
</Fragment>
</Router>
);
}
export default App;
AuthenticationApp.js
import { Route, Redirect, Switch, useLocation } from "react-router-dom";
import TransitionGroup from "react-transition-group/TransitionGroup";
import CSSTransition from "react-transition-group/CSSTransition";
import { Suspense } from "react";
import LoadingSpinner from "./shared/UIElements/LoadingSpinner";
import Auth from "./Auth/page/Auth";
const AuthenticationApp = ({}) => {
const location = useLocation();
return (
<TransitionGroup>
<CSSTransition timeout={1250} classNames="fade" key={location.pathname}>
<Suspense
fallback={
<div className="center">
<LoadingSpinner></LoadingSpinner>
</div>
}
>
<Switch>
<Route path="/" exact>
<Auth />
</Route>
<Redirect to="/" />
</Switch>
</Suspense>
</CSSTransition>
</TransitionGroup>
);
};
export default AuthenticationApp;
TaskApp.js
import { Route, Redirect, Switch, useLocation } from "react-router-dom";
import TransitionGroup from "react-transition-group/TransitionGroup";
import CSSTransition from "react-transition-group/CSSTransition";
import { Suspense } from "react";
import LoadingSpinner from "./shared/UIElements/LoadingSpinner";
import TaskMain from "./tasks/page/TaskMain";
import NewTask from "./tasks/page/NewTask";
import UpdateTask from "./tasks/page/UpdateTask";
import TaskFilter from "./tasks/page/TaskFilter";
const TaskApp = () => {
const location = useLocation();
return (
<TransitionGroup>
<CSSTransition timeout={1250} classNames="fade" key={location.pathname}>
<Suspense
fallback={
<div className="center">
<LoadingSpinner></LoadingSpinner>
</div>
}
>
<Switch>
<Route path="/" exact>
<TaskMain />
</Route>
<Route path="/tasks/new" exact>
<NewTask />
</Route>
<Route path="/tasks/update/:id" exact>
<UpdateTask />
</Route>
<Route path="/items" exact>
<TaskFilter />
</Route>
<Redirect to="/" />
</Switch>
</Suspense>
</CSSTransition>
</TransitionGroup>
);
};
export default TaskApp;

Why is component not connecting to the redux store?

I am trying to connect some component (USERS) to my store. I will show you each step.
First of all i create my store in index.js:
// composeWithDevTools helps to follow state changes, remove in production
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const sagaMiddleware = createSagaMiddleware();
const store = createStore(reducers, composeEnhancers(applyMiddleware(sagaMiddleware)));
//sagaMiddleware.run(usersSaga);
console.log('MYSTORE: ', store);
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root'),
);
My reducer is coded in the following way:
import { combineReducers } from 'redux';
import usersReducer from './usersReducer';
export default combineReducers({
users: usersReducer,
});
Now my App.js file looks like this:
import React from 'react';
import { HashRouter, Route, Redirect } from 'react-router-dom';
import { AuthorisationMails } from './route-components/AuthorisationMails.js';
import { ChangePassword } from './route-components/ChangePassword.js';
import { Credits } from './route-components/Credits.js';
import { Graphs } from './route-components/Graphs.js';
import { Groups } from './route-components/Groups.js';
import { HeaderBar } from './components/HeaderBar.js';
import { Home } from './route-components/Home.js';
import { Login } from './route-components/Login.js';
import { MailServers } from './route-components/MailServers.js';
import { MailStatus } from './route-components/MailStatus.js';
import { Options } from './route-components/Options.js';
import { StatusMails } from './route-components/StatusMails.js';
import { Users } from './route-components/Users.js';
const App = () => (
<div>
<HashRouter>
<HeaderBar />
<Route path="/">
<Redirect to="/login" />
</Route>
<Route path="/login" component={Login} />
<Route path="/dashboard_user" component={Users} />
</HashRouter>
</div>
);
export default App;
In Users, i try to connect to the store with a mapstateToProps and connect as you see here:
import React, { Component } from 'react';
import { withRouter } from 'react-router-dom';
import { connect } from 'react-redux';
import * as actions from '../redux/actions';
export class Users extends Component {
componentDidMount() {
console.log('USERPROPS: ', this.props);
}
render() {
return <div>Users</div>;
}
}
const mapStateToProps = state => {
console.log('USERSSTATE: ', state.user);
return {
users: state.userReducer,
};
};
export default withRouter(connect(mapStateToProps)(Users));
The problem here is that somehow i am connecting in the wrong way, since the console.log of USERPROPS does not contain a property user. It contains history location and match.
I tried connecting by using the following url https://react-redux.js.org/api/connect.
Any idea on why my component is not connecting to the store?
Solved it, i removed the brackets when importing components, thus for example:
import { Credits } from './route-components/Credits.js' => import Credits from './route-components/Credits.js'
I think you might need to use state.users.user:
const mapStateToProps = state => {
return {
users: state.users.user,
};
};

Upgrading from createContainer to withTracker with React Router V4

I upgraded meteor and I started receiving deprecation warning for createContainer(). As a result, I've tried to implement withTracker however now I'm getting Component(...): A valid React element (or null) must be returned. You may have returned undefined, an array or some other invalid object.. I'm not sure what I'm missing here, can someone point out my error.
Path: App.jsx
import { Meteor } from 'meteor/meteor';
import React from 'react';
import PropTypes from 'prop-types';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import { withTracker } from 'meteor/react-meteor-data';
// IsCandidate Spefic Routes
import TestContainer from '../../containers/candidate/TestContainer';
const App = appProps => (
<Router>
<ScrollToTop>
<div className="bgColor">
<NavBar {...appProps} />
<Grid className="main-page-container">
<Switch>
{/* candidate routes */}
<IsCandidate exact path="/candidate/testpage/:id" component={withTracker(TestContainer)} {...appProps} />
{/* IsPublic routes */}
<Route render={function () {
return <p>Page not found</p>;
}}
/>
</Switch>
</Grid>
</div>
</ScrollToTop>
</Router>
);
App.propTypes = {
loggingIn: PropTypes.bool,
isCandidate: PropTypes.bool
};
export default createContainer(() => {
const loggingIn = Meteor.loggingIn();
return {
loggingIn,
isCandidate: !loggingIn && !!Meteor.userId() && !!Roles.userIsInRole(Meteor.userId(), 'isCandidate'),
};
}, App);
Path: IsCandidate.jsx
import React from 'react';
import PropTypes from 'prop-types'; // ES6
import { Route, Redirect } from 'react-router-dom';
const IsCandidate = ({ loggingIn, isCandidate, component: Component, ...rest }) => (
<Route
{...rest}
render={(props) => {
if (loggingIn) return <div />;
return isCandidate ?
(<Component loggingIn={loggingIn} isCandidate={isCandidate} {...rest} {...props} />) :
(<Redirect to="/login" />);
}}
/>
);
IsCandidate.propTypes = {
loggingIn: PropTypes.bool,
isCandidate: PropTypes.bool,
component: PropTypes.func
};
export default IsCandidate;
Path: Testcontainer.jsx
import { Meteor } from 'meteor/meteor';
import { withTracker } from 'meteor/react-meteor-data';
import { Test } from '../../../api/test/test';
import TestPage from '../../pages/candidate/TestPage';
export default TestContainer = withTracker(({ match }) => {
const testHandle = Meteor.subscribe('test', match.params.id);
const loadingTest = !testHandle.ready();
const testCollection = Test.findOne(match.params.id);
const testExist = !loadingTest && !!testCollection;
return {
loadingTest,
testExist,
testCollection: testExist ? testCollection : {}
};
}, TestPage);
Update
export default withTracker(() => {
const loggingIn = Meteor.loggingIn();
return {
loggingIn,
isCandidate: !loggingIn && !!Meteor.userId() && !!Roles.userIsInRole(Meteor.userId(), 'isCandidate'),
isEmployer: !loggingIn && !!Meteor.userId() && !!Roles.userIsInRole(Meteor.userId(), 'isEmployer'),
isAdmin: !loggingIn && !!Meteor.userId() && !!Roles.userIsInRole(Meteor.userId(), 'isAdmin')
};
})(App);
In App.jsx you import withTracker but use createContainer.
withTracker takes only one argument (your reactive function) and wraps your child component where createContainer took 2 arguments (function and component).
createContainer(fn, C);
withTracker(fn)(C);
EDIT
Remove the withTracker call in App.js from this line:
<IsCandidate exact path="/candidate/testpage/:id" component={withTracker(TestContainer)} {...appProps} />
so it becomes
<IsCandidate exact path="/candidate/testpage/:id" component={TestContainer} {...appProps} />
How about it?

Resources