react-transition-group not work until reload the page - css

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;

Related

How to Call API In NextJS Using Redux With SSR?

Need One Help i am trying to call api in nextjs using
redux(Here,SSR is not possible)
and getServerSideProps(Here, SSR is Possible but without redux) in both case API Called Successfully. If i used it individually bot are working well but now i want to merge it both and i have read about next-redux-wrapper but when i am integrate it.
API Called Using GetServerSideProps()
index.js
`
import Product from "./product-cart";
import React from "react";
import styles from "../styles/Product.module.css";
import axios from "axios";
const Home = ({ products, loading }) => {
return (
<>
{loading ? (
<h1>Loading...</h1>
) : (
<>
<div className={styles.banner}>
<p>Welcome to ecommerce!</p>
<h1>FIND AMAZING PRODUCT BELOW</h1>
<a href="#container">
<button>Scroll</button>
</a>
</div>
<h2 className={styles.homeHeading}>Featured Product</h2>
<div className={styles.container} id="container">
{products &&
products.map((products) => (
<Product key={products._id} products={products} />
))}
</div>
</>
)}
</>
);
};
export default Home;
export async function getServerSideProps(context) {
let link = `http://localhost:5000/api/v1/product`;
const { data } = await axios.get(link);
return { props: { products: data.product } };
}
`
API Called Using Redux
_app.js
`
import { Provider } from "react-redux";
import store, { wrapper } from "../redux/store";
import "../styles/globals.css";
function MyApp({ Component, pageProps }) {
return (
<>
<Provider store={store}>
<Component {...pageProps} />
</Provider>
</>
);
}
// export default wrapper.withRedux(MyApp);
export default MyApp;
`
index.js(GetProduct() Created In Action File)
`
import Product from "./product-cart";
import React from "react";
import styles from "../styles/Product.module.css";
import { clearErrors, getProduct } from "../redux/Actions/ProductAction";
import { useSelector, useDispatch, connect } from "react-redux";
import axios from "axios";
import { wrapper } from "../redux/store";
const Home = ({ products, loading }) => {
const { loading, error, products } = useSelector(
(state) => state.products || {}
);
const dispatch = useDispatch();
React.useEffect(() => {
if (error) {
dispatch(clearErrors());
}
dispatch(getProduct());
}, [dispatch]);
return (
<>
{loading ? (
<h1>Loading...</h1>
) : (
<>
<div className={styles.banner}>
<p>Welcome to ecommerce!</p>
<h1>FIND AMAZING PRODUCT BELOW</h1>
<a href="#container">
<button>Scroll</button>
</a>
</div>
<div suppressHydrationWarning>
{process.browser ? "browser" : "server"}
</div>
<h2 className={styles.homeHeading}>Featured Product</h2>
<div className={styles.container} id="container">
{products &&
products.map((products) => (
<Product key={products._id} products={products} />
))}
</div>
</>
)}
</>
);
};
export default Home;
`
If you need more information let me know
TypeError: makeStore is not a function
enter image description here
Try to Use Next-redux-wrapper but not able to find solution regarding that
_app.js
import { Provider } from "react-redux";
import store, { wrapper } from "../redux/store";
import "../styles/globals.css";
function MyApp({ Component, pageProps }) {
return (
<>
<Provider store={store}>
<Component {...pageProps} />
</Provider>
</>
);
}
export default wrapper.withRedux(MyApp);
store.js
import {
createStore,
combineReducers,
applyMiddleware,
legacy_createStore,
} from "redux";
import thunk from "redux-thunk";
// import { createStore } from "redux";
import { createWrapper, HYDRATE } from "next-redux-wrapper";
import { composeWithDevTools } from "redux-devtools-extension";
import {
adminProductEDReducer,
AdminProductReducer,
newProductReducer,
newReviewReducer,
productDetailReducer,
productReducer,
} from "./Reducers/ProductReducer";
import {
userReducer,
profileReducer,
forgotPasswordReducer,
allUserReducer,
userDetailsReducer,
} from "./Reducers/UserReducers";
const reducer = combineReducers({
products: productReducer,
productDetails: productDetailReducer,
adminProduct: AdminProductReducer,
newProduct: newProductReducer,
user: userReducer,
profile: profileReducer,
forgotPassword: forgotPasswordReducer,
newReview: newReviewReducer,
EditDelProduct: adminProductEDReducer,
allUser: allUserReducer,
userDetail: userDetailsReducer,
});
// if the value is in cart otherwise it will be blank and we can store cartitems in localstorage
let initialState = {};
const middleware = [thunk];
const store = legacy_createStore(
reducer,
initialState,
composeWithDevTools(applyMiddleware(...middleware))
);
// export an assembled wrapper
export const wrapper = createWrapper(store, { debug: true });
export default store;

Can't change variable when using Firebase onAuthStateChanged

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> */

Code works in local dev and not in stackblitz and sandbox

Goal:
Display the content of the code in relation to
<Router>
{isAuthenticated ? authenticatedRoutes : nonAuthenticatedRoutes}
</Router>
Problem:
When I use codesandbox or Stackblitz it wont display the content. However, when I use my local computer with VS code.
Same code that is used in my local development is the same for the sandbox and stackblitz.
In the end the result display in local development but not in codesandbox stand stackblitz.
However, it creates a lot of message and error about
"Warning: Maximum update depth exceeded. This can happen when a component calls setState inside useEffect, but useEffect either doesn't have a dependency array, or one of the dependencies changes on every render."
Question:
How should it be solved in order to be displayed at stackblitz and also not displaying many message.
Info:
*The foundation of the code is from this webpage (https://stackblitz.com/edit/react-ts-conditional-route-e9gscp)
*If you dont want to show the error message, exchange the code to
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
</div>
Stackblitz:
https://stackblitz.com/edit/react-ts-xjaspz
Sandbox:
https://codesandbox.io/s/confident-swanson-uie1n1
Thank you!
index.tsx
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
App.tsx
import React, { useEffect, useState } from 'react';
import { BrowserRouter as Router, Link, Route, Routes, Navigate } from 'react-router-dom';
import Login from './Login';
import Home from './Home';
const App = () => {
const [isAuthenticated, setIsAuthenticated] = useState<boolean>(false);
useEffect(() => {
}, [isAuthenticated]);
const handle_login = () => {
setIsAuthenticated(true);
};
const handle_logout = () => {
setIsAuthenticated(false);
};
const authenticatedRoutes = (
<React.Fragment>
<Routes>
<Route
path="/home"
element={<Home handle_logout={handle_logout} />}
/>
</Routes>
<Navigate to="/home" />
</React.Fragment>
);
const nonAuthenticatedRoutes = (
<React.Fragment>
<Routes>
<Route
path="/login"
element={<Login handle_login={handle_login} />}
/>
</Routes>
<Navigate to="/login" />
<br />
<br />
</React.Fragment>
);
return (
<Router>
{isAuthenticated ? authenticatedRoutes : nonAuthenticatedRoutes}
</Router>
);
};
export default App;
*
{isAuthenticated ? authenticatedRoutes : nonAuthenticatedRoutes}
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
</div>
*/
login.tsx
import React from "react";
interface LoginProps {
handle_login: () => void;
}
const Login: React.FC<LoginProps> = props => {
return (
<React.Fragment>
<title> Login </title>
<div className="container">
<strong>login page</strong> <br />
<br />
<button onClick={props.handle_login}> Login </button>
</div>
</React.Fragment>
);
};
export default Login;
Home.tsx
import React from 'react';
interface HomeProps {
handle_logout: () => void;
}
const Home: React.FC<HomeProps> = (props) => {
return (
<React.Fragment>
<header>
{/* <h2>Home </h2> */}
<button slot="end" onClick={props.handle_logout}>
{' '}
Logout{' '}
</button>
</header>
<title> Home </title>
<div className="container">
<strong>Home page</strong>
<p>Click logout on the titlebar to logout </p>
</div>
</React.Fragment>
);
};
export default Home;
https://stackblitz.com/edit/react-ts-eghbyc?file=index.tsx
App.tsx
import React, { useEffect, useState } from 'react';
import { BrowserRouter as Router, Route, Routes, Navigate } from 'react-router-dom';
import Home from './Home';
import Login from './Login';
const App: React.FC = () => {
const [isAuthenticated, setIsAuthenticated] = useState<boolean>(false);
useEffect(() => {
console.log('Authentication state - ', isAuthenticated);
}, [isAuthenticated]);
const handle_login = () => {
setIsAuthenticated(true);
};
const handle_logout = () => {
setIsAuthenticated(false);
};
const authenticatedRoutes = (
<React.Fragment>
<Routes>
<Route
path="/home"
element={<Home handle_logout={handle_logout} />}
/>
<Route
path="*"
element={<Navigate to="/home" />}
/>
</ Routes>
</React.Fragment>
);
const nonAuthenticatedRoutes = (
<React.Fragment>
<Routes>
<Route
path="/login"
element={<Login handle_login={handle_login} />}
/>
<Route
path="*"
element={<Navigate to="/login" />}
/>
</ Routes>
<br />
<br />
<br />
<br />
</React.Fragment>
);
return (
<Router>
{/* <IonRouterOutlet> */}
{isAuthenticated ? authenticatedRoutes : nonAuthenticatedRoutes}
{/* </IonRouterOutlet> */}
</Router>
);
};
export default App;
Home.tsx
import React from 'react';
interface HomeProps {
handle_logout: () => void;
}
const Home: React.FC = (props) => {
return (
<React.Fragment>
{/* Home */}
<button slot="end" onClick={props.handle_logout}>
{' '}
Logout{' '}
</button>
</header>
<title> Home </title>
<div className="container">
<strong>Home page</strong>
<p>Click logout on the titlebar to logout </p>
</div>
</React.Fragment>
);
};
export default Home;
index.tsx
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
Login.tsx
import React from "react";
interface LoginProps {
handle_login: () => void;
}
const Login: React.FC<LoginProps> = props => {
return (
<React.Fragment>
<title> Login </title>
<div className="container">
<strong>login page</strong> <br />
<br />
<button onClick={props.handle_login}> Login </button>
</div>
</React.Fragment>
);
};
export default Login;

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?

ReactCSSTransitionGroup leave animation not applying to Route

Entering animations are applied correctly. Component seems to unmount prior to applying any leave, leave-active classes.
componentWillMount() {
this.setState({
routes: [(<Route exact path='/' component={HomeView}/>),
(<Route exact path='/account' component={YourAccountView}/>),
(<Route exact path='/settings' component={SettingsView}/>),
(<Route exact path='/about' component={AboutView}/>),
(<Route exact path='/machine/:_id' component={MachineDetailView}/>),
(<Route exact path='/floorview' component={FloorView}/>)]
})
}
render() {
return (
<div>
<NavBar/>
<div style={{position: 'relative', flexGrow: 1 , marginTop:40+'px'}}>
<ReactCSSTransitionGroup
transitionName="pageSlider"
transitionEnter={true}
transitionLeave={true}
transitionEnterTimeout={500}
transitionLeaveTimeout={500}>
{this.state.routes
.filter((e)=> e.props.path===this.context.router.history.location.pathname )
.map((e)=> React.cloneElement(e, { key: this.context.router.history.location.pathname} ))}
</ReactCSSTransitionGroup>
</div>
</div>
);
}
I can't tell if this is a ReactCSSTransitionGroup thing, or a React-Router v4 mounting/unmounting thing. Has anyone run into and solved similar issue?
this case works:
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import {BrowserRouter, Route} from 'react-router-dom';
import App from './App';
import './index.css';
ReactDOM.render(
<BrowserRouter>
<Route path="/" component={App}/>
</BrowserRouter>
,
document.getElementById('root')
);
App.js
import React, { Component } from 'react';
import { Switch, Route, Link } from 'react-router-dom';
import ReactCSSTransitionGroup from 'react-addons-css-transition-group';
import './App.css';
const One = ({match}) => (
<h2>{match.url}</h2>
)
const Two = ({match}) => (
<h2>{match.url}</h2>
)
const Three = ({match}) => (
<h2>{match.url}</h2>
)
const Four = ({match}) => (
<h2>{match.url}</h2>
)
const MyNav = () => (
<div>
<Link to='/One'>One</Link>
<Link to='/Two'>Two</Link>
<Link to='/Three'>Three</Link>
<Link to='/Four'>Four</Link>
</div>
)
class App extends Component {
componentWillMount() {
this.setState({routeKey:this.props.location.pathname})
this.setState({routes: [
(<Route exact path="/One" component={One}/>),
(<Route exact path="/Two" component={Two}/>),
(<Route exact path="/Three" component={Three}/>),
(<Route exact path="/Four" component={Four}/>)
]})
}
render() {
return (
<div className="App">
<div>
<MyNav/>
<ReactCSSTransitionGroup
transitionName="PageSlider"
transitionEnterTimeout={0}
transitionLeaveTimeout={150}>
<Switch key={this.props.location.pathname}>
<Route exact path="/One" component={One}/>
<Route exact path="/Two" component={Two}/>
<Route exact path="/Three" component={Three}/>
<Route exact path="/Four" component={Four}/>
</Switch>
</ReactCSSTransitionGroup>
</div>
</div>
);
}
componentWillReceiveProps(newProps) {
this.setState({routeKey:newProps.location.pathname})
}
}
export default App;
specify .PageSlider-enter, .PageSlider-enter.PageSlider-enter-active, .PageSlider-leave, .PageSlider-leave.PageSlider-leave-active accordingly

Resources