i am trying create a transition screen from one page to the other
function MainPage(){
return (
<div>
{pagestate.navigating == "true" ? (
<FadeIn>
<div className="d-flex justify-content-center align-items-center">
<h1>signing you in ....</h1>
<Link to="/" color="black" >sign in</Link>
{pagestate.loading =="false" ? (
<Lottie options={defaultOptions} height={120} width={120} />
) : (
<Lottie options={defaultOptions2} height={220} width={120} />
)}
</div>
</FadeIn>
) : (
<div>
<h1>hello world</h1>
<Link to="/" color="black" >sign in</Link>
</div>
)}
The code works fine but I want it to navigate to /page2 when pagestate.loading = "false". I was able to achieve the page navigation with using
const history = useHistory()
then call navigation like
history.push('/page2')
I tried couple of method but could not get it work inside the transition logic.
How can I incorporate to the navigation into a new page after loading state has been changed to false in the transition logic above?
Encountered that a couple of days ago, i found a solution to it but it’s kinda weird,i’ve done it using redux, i’ve made a Link Component Called LinkWithAnimation,created a reducer as RouteReducer which will store current transition state, 2 states:
First one is For Transitioning In.
Second one is For Transitioning Out.
Wrapped my application with a div and passed the Transition that’s stored in redux, everytime LinkWithAnimation Is clicked This Is What Happens:
Dispatch An Action For Transitioning In
Wait(Delay) Till the Transition Has Finished(Depending On The Duration Of It)
Dispatch An Action for Transitioning Out.
And then push the new path using History API.
Note: Make Use Of Redux Thunk.
ActionTypes.js
export const ActionsType = {
...otherActions,
ANIMATION_IN: "animation-in",
ANIMATION_OUT: "animation-out",
};
ActionsCreator.js
import { ActionsType } from "./ActionsType.js";
import { history } from "../index.js";
export const ActionsCreator = {
...otherActionCreators,
userLogout: () => ({ type: ActionsType.LOGOUT }),
animateIn: () => ({ type: ActionsType.ANIMATION_IN }),
animateOut: () => ({ type: ActionsType.ANIMATION_OUT }),
pageTransition: (duration, path) => {
return async (dispatch) => {
const delay = async () => {
return new Promise((resolve) => setTimeout(resolve, duration));
};
dispatch(ActionsCreator.animateOut());
await delay();
dispatch(ActionsCreator.animateIn());
history.push(path);
};
},
};
index.js
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import { Router } from "react-router-dom";
import { createBrowserHistory } from "history";
export const history = createBrowserHistory();
ReactDOM.render(
<Router history={history}>
<React.StrictMode>
<App />
</React.StrictMode>
</Router>,
document.getElementById("root")
);
LinkWithAnimation.js
import React, { useRef, useEffect } from "react";
import { Link } from "react-router-dom";
import { ActionsCreator } from "../actions/ActionsCreator.js";
import { connect } from "react-redux";
const LinkWithAnimation = ({
className,
additionalFunction,
PageTransitioning,
to,
children,
style,
component,
ReactTo,
disabled,
}) => {
const LinkRef = useRef();
// This Effect To Handle Page Transition Once The User Is Signed In
useEffect(() => {
if (ReactTo === true) {
LinkRef.current.click();
}
}, [ReactTo]);
const componentProp =
component !== undefined
? {
component: component,
}
: {};
return (
<>
<Link
onClick={async () => {
if (disabled) return;
PageTransitioning(230, to);
if (additionalFunction !== undefined) {
additionalFunction();
}
}}
ref={LinkRef}
className={className}
style={{ ...style }}
{...componentProp}
>
{children}
</Link>
</>
);
};
const mapDispatchToProps = (dispatch) => ({
PageTransitioning: (duration, path) => {
dispatch(ActionsCreator.pageTransition(duration, path));
},
});
export default connect(null, mapDispatchToProps)(LinkWithAnimation);
Main.js
import React, { Fragment } from "react";
import { Switch, Route } from "react-router-dom";
import { connect } from "react-redux";
import Homepage from "./Homepage/Homepage.js";
import Signup from "./Signup/Signup.js";
import UserInterface from "./UserInterface/UserInterface.js";
import { SignIn } from "./SignIn/SignIn.js";
import { useRouteTransitionScroll } from "../hooks/useRouteTransitionScroll.js";
const Main = ({ keyframe }) => {
useRouteTransitionScroll({
from: "/signup",
to: "/home",
scroll_y: 650,
});
return (
<Switch component={Fragment}>
<div
style={{
animationName: keyframe,
animationDuration: "250ms",
animationTimingFunction: "linear",
}}
>
<Route path="/mainpage">
<UserInterface />
</Route>
<Route path="/home">
<Homepage />
</Route>
<Route path="/signin">
<SignIn />
</Route>
<Route path="/signup">
<Signup />
</Route>
</div>
</Switch>
);
};
const mapStateToProps = (state) => ({
keyframe: state.Route.animationName,
});
export default connect(mapStateToProps)(Main);
Related
Before I used react-router-dom and I hadn't any problem and I changed my route without any problem.
But now I bring hook inside of my project and I got a problem.
When I use <NavLink>, my route changes but it does not render anything from my component. When I refresh my page, the component will appear.
My App.js:
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
const routes={
route: `/main/symbol/:title/:id`,
exact: true,
component: Symbol,
},
{
route: `/main/symbolDetails/:title/:id`,
exact: true,
component: SymbolDetails,
},
render(){
<Router>
<Switch>
{routes.map((route, k) => (
<Route
key={k}
exact={route.exact}
path={route.route}
component={route.component}
/>
))}
</Switch>
</Router>
}
My Home.js:
(in this component I use navlink for changing my page)
import GridContainer from "../../../components/Grid/GridContainer.js";
import "perfect-scrollbar/css/perfect-scrollbar.css";
// #material-ui/core components
import { makeStyles } from "#material-ui/core/styles";
// core components
import Navbar from "../../../components/Navbars/Navbar.js";
import Sidebar from "../../../components/Sidebar/Sidebar.js";
const useStyles = makeStyles(styles);
export default function Admin({ ...rest }) {
// styles
const classes = useStyles();
const [data, setData] = useState([]);
useEffect(() => getSymbolGroup(), []);
const getSymbolGroup = async () => {
let { data } = await symbolGroup.getSymbolGroup();
setData(data.data);
// console.log("data", data);
};
return (
<div className={classes.wrapper}>
<Sidebar
logoText={"Creative Tim"}
logo={logo}
color={color}
{...rest}
/>
<div className={classes.mainPanel}>
<Navbar
/>
<div className={classes.content}>
<div className={classes.container}>
<GridContainer>
{data &&
data.length &&
data.map((x, key) => {
return (
<div className="Subscrip Bshadow ">
<NavLink
to={`/main/symbol/${x.title}/${x.id}`}
className="a rightanime display awidth flexd"
exact
>
<div className="">
<div className="iconpro display">
<img
className="imgwidth "
src={`http://api.atahlil.com/Core/Download/${x.fileId}`}
/>
</div>
</div>
<div className="">
<p style={{ color: "#a3b0c3", width: "100%" }}>
{x.title}
</p>
</div>
</NavLink>
</div>
);
})}
</GridContainer>
</div>
</div>
)}
I realized my problem.
as I say it was correct when I use in class component.
it is not correct because of my useEffect (hook).
I had to use accolade (I mean {}) after use UseEffect in Home.js component.
home.js
useEffect(() => getSymbolGroup(), []); //it is not correct and I need to refresh my page to render
and the way I had to use useEffect is:
useEffect(() => {
getSymbolGroup();
}, []);
// its correct and does not need to refresh page
Pretty much the title, when I add
useEffect(() => {
const fetchData = async () => {
const result = await fetch('http://localhost.com/ping');
console.log(result)
};
fetchData();
}, []);
to my component, the page renders properly and then immediately blanks out. Not sure what I did wrong since it's literally the same in the React Documentation.
Full component:
import React from 'react';
import { useEffect } from 'react';
const Test = () => {
useEffect(() => {
const fetchData = async () => {
const result = await fetch('http://localhost.com/ping');
console.log(result)
};
fetchData();
}, []);
return (
<>
<h1>Test</h1>
</>
);
};
export default Test;
App
import { hot } from 'react-hot-loader/root';
import React from 'react';
import Navigation from './components/Navigation/Navigation.jsx';
const App = () => {
return (
<>
<div>Stuff</div>
<Navigation></Navigation>
</>
);
};
export default hot(App);
Navigation
/* eslint-disable react/display-name */
import { BrowserRouter as Router, Route, Link, Switch } from 'react-router-dom';
import React from 'react';
import Home from './Home';
import Login from './Login';
import Logout from './Logout';
import Faq from './Faq';
import Dashboard from './Dashboard';
import Test from './Test';
const Navigation = () => {
const isLoggedIn = false;
return (
<>
<Router>
<div>
<ul>
<li>
<Link to='/'>Home</Link>
</li>
<li>
{isLoggedIn ? (
<Link to='/auth/logout'>Logout</Link>
) : (
<Link to='/auth/login'>Login</Link>
)}
</li>
<li>
<Link to='/auth/dashboard'>Dashboard</Link>
</li>
<li>
<Link to='/faq'>FAQ</Link>
</li>
<li>
<Link to='/test'>Test</Link>
</li>
</ul>
</div>
<Switch>
<Route exact path='/'>
<Home />
</Route>
<Route exact path='/auth/login'>
<Login />
</Route>
<Route path='/auth/logout'>
<Logout />
</Route>
<Route path='/auth/dashboard'>
<Dashboard />
</Route>
<Route path='/faq'>
<Faq />
</Route>
<Route path='/test'>
<Test />
</Route>
</Switch>
</Router>
</>
);
};
export default Navigation;
I have to write some stuff here because stack overflow decided that i am not allowed to post the code that people asked for ...
Try with
useEffect(() => {
const fetchData = async () => {
try {
const result = await fetch('http://localhost.com/ping');
console.log(result)
} catch (e){
console.log(e)
}
};
fetchData();
});
Instead of
useEffect(() => {
const fetchData = async () => {
const result = await fetch('http://localhost.com/ping');
console.log(result)
};
fetchData();
}, []);
You could wrap the fetch call in try/catch block to run your code smoothly.
And use one react import instead of two separate.
import React, {useEffect} from 'react';
const Test = () => {
useEffect(() => {
const fetchData = async () => {
try{
const result = await fetch('http://localhost/ping');
console.log(result)
} catch(error) {
console.log(error.message);
}
};
fetchData();
}, []);
return (
<>
<h1>Test</h1>
</>
);
};
export default Test;
After poking around a bit I finally got an error message : "Test.jsx:26 Uncaught ReferenceError: regeneratorRuntime is not defined"
To fix that install regenerator-runtime and require it globally. Read the readme of regenerator-runtime if you are unsure on how to do that.
I am trying to manage session after successful login while redirecting to some page on form submit.
I would do this usually, in a class component:
componentDidMount() {
if (context.token) {
return <Redirect to="/" />
}
}
But I want to use React hooks, therefore; the following code is not redirecting anywhere:
import React, { useEffect } from "react";
import ReactDOM from "react-dom";
import { BrowserRouter, Switch, Route, Redirect, Link } from "react-router-dom";
es6
const HomePage = props => (
<div>
<h1>Home</h1>
</div>
);
const AboutUsPage = props => {
useEffect(() => {
redirectTo();
}, []);
return (
<div>
<h1>About us</h1>
</div>
);
};
function redirectTo() {
return <Redirect to="/" />;
}
function App() {
return (
<div className="App">
<BrowserRouter>
<nav>
<Link to="/">Home</Link>
<Link to="/us">About us</Link>
</nav>
<Switch>
<Route exact path="/" component={HomePage} />
<Route exact path="/us" component={AboutUsPage} />
</Switch>
</BrowserRouter>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Working sandbox: https://codesandbox.io/s/blue-river-6dvyv?fontsize=14
I have read that if the hook useEffect() returns a function it will only work when the component unmounts. But it should redirect when the component is being mounted.
Any suggestions? Thanks in advance.
You could set redirect variable on the state and based on it redirect in render:
const AboutUsPage = props => {
const [redirect, setRedirect] = useState(false);
useEffect(() => {
setRedirect(true); // Probably need to set redirect based on some condition
}, []);
if (redirect) return redirectTo();
return (
<div>
<h1>About us</h1>
</div>
);
};
You could have it so that the component selectively renders the page based on whether or not the page is given a token.
const AboutUsPage = ({token}) => (
token ? (
<Redirect to="/" />
) : (
<div>
<h1>About us</h1>
</div>
)
);
However, if you would still like to use context when implementing this with React Hooks you can read up on how to use context with hooks in this article. It shows you how you can incorporate context into React with only a few lines of code.
import React, {createContext, useContext, useReducer} from 'react';
export const StateContext = createContext();
export const StateProvider = ({reducer, initialState, children}) =>(
<StateContext.Provider value={useReducer(reducer, initialState)}>
{children}
</StateContext.Provider>
);
export const useStateValue = () => useContext(StateContext);
Done with hooks and context, your AboutUsPage component would resemble something like this.
import { useStateValue } from './state';
const AboutUsPage = () => {
const [{token}, dispatch] = useStateValue();
return token ? (
<Redirect to="/" />
) : (
<div>
<h1>About us</h1>
</div>
);
};
import {Redirect, Switch} from "react-router-dom";
and inside Switch....
<Switch>
<Redirect exact from="/" to="/home" />
</Switch>
This solved my issue.
I have this router animation working on page load but when I use the navbar to navigate it changes the web address but the pages don't change or take extremely long to change.
import React, { useContext } from "react";
import { createBrowserHistory } from "history";
import { Router, Route, Switch, __RouterContext } from "react-router-dom";
import { useTransition, animated } from "react-spring";
import "assets/scss/material-kit-react.scss?v=1.4.0";
// pages for this product
import LandingPage from "views/LandingPage/LandingPage.jsx";
import ProfilePage from "views/ProfilePage/ProfilePage.jsx";
var hist = createBrowserHistory();
const App = () => {
const { location } = useContext(__RouterContext);
const transitions = useTransition(location, location => location.pathname, {
from: { opacity: 0, transform: "translate(100%,0)" },
enter: { opacity: 1, transform: "translate(0%,0)" },
leave: { opacity: 0, transform: "translate(-50%,0)" }
});
return (
<>
{transitions.map(({ item, props, key }) => (
<animated.div key={key} style={props}>
<Router history={hist}>
<Switch location={item}>
<Route path="/profile-page" component={ProfilePage} />
<Route path="/" component={LandingPage} />
</Switch>
</Router>
</animated.div>
))}
</>
);
};
export default App;
This is how my NavLink is structured
<Link
exact
to="/profile-page"
className={classes.link}
activeClassName="active"
>
I tried to recreate your problem. I think your problem could be, that you use Router outside and inside the App as well. Because useContext would not work without an outer router.
So the solution is to remove router from the render of the app. Here is my full working example:
import React, { useContext } from 'react';
import { createBrowserHistory } from 'history';
import {
Route,
Switch,
Link,
__RouterContext,
BrowserRouter
} from 'react-router-dom';
import { useTransition, animated } from 'react-spring';
import ReactDOM from 'react-dom';
function App() {
return (
<BrowserRouter>
<Home />
</BrowserRouter>
);
}
// pages for this product
const LandingPage = () => {
return (
<div>
<h1>LandingPage</h1>
<Link to="/profile-page">profile</Link>
</div>
);
};
const ProfilePage = () => {
return (
<div>
<h1>Profile</h1>
<Link to="/">main</Link>
</div>
);
};
const Home = () => {
const { location } = useContext(__RouterContext);
const transitions = useTransition(location, location => location.pathname, {
from: {
position: 'absolute',
width: '100%',
opacity: 0,
transform: 'translate(100%,0)'
},
enter: { opacity: 1, transform: 'translate(0%,0)' },
leave: { opacity: 0, transform: 'translate(-50%,0)' }
});
return (
<>
{transitions.map(({ item, props, key }) => (
<animated.div key={key} style={props}>
<Switch location={item}>
<Route path="/profile-page" component={ProfilePage} />
<Route path="/" component={LandingPage} />
</Switch>
</animated.div>
))}
</>
);
};
ReactDOM.render(<App />, document.getElementById('root'));
export default App;
You can try it here: https://codesandbox.io/s/sleepy-wozniak-b07jp
As a newbie Reacteur, I have been following this tutorial to build a simple login form with reactjs. Everything works fine and it works as intended. The whole tutorial is based on a signle script.
Here is the final code (from the tutrial):
import React from 'react'
import {
BrowserRouter as Router,
Route,
Link,
Redirect,
withRouter
} from 'react-router-dom'
const authenticator = {
isAuthenticated: false,
authenticate(cb) {
this.isAuthenticated = true
setTimeout(cb, 100)
},
signout(cb) {
this.isAuthenticated = false
setTimeout(cb, 100)
}
}
const Public = () => <h3>Public</h3>
const Protected = () => <h3>Protected</h3>
class Login extends React.Component {
state = {
redirectToReferrer: false
}
login = () => {
authenticator.authenticate(() => {
this.setState(() => ({
redirectToReferrer: true
}))
})
}
render() {
const { from } = this.props.location.state || { from: { pathname: '/' } }
const { redirectToReferrer } = this.state
if (redirectToReferrer === true) {
return <Redirect to={from} />
}
return (
<div>
<p>You must log in to view the page</p>
<button onClick={this.login}>Log in</button>
</div>
)
}
}
const PrivateRoute = ({ component: Component, ...rest }) => (
<Route {...rest} render={(props) => (
fakeAuth.isAuthenticated === true
? <Component {...props} />
: <Redirect to={{
pathname: '/login',
state: { from: props.location }
}} />
)} />
)
const AuthButton = withRouter(({ history }) => (
fakeAuth.isAuthenticated ? (
<p>
Welcome! <button onClick={() => {
fakeAuth.signout(() => history.push('/'))
}}>Sign out</button>
</p>
) : (
<p>You are not logged in.</p>
)
))
export default function AuthExample () {
return (
<Router>
<div>
<AuthButton/>
<ul>
<li><Link to="/public">Public Page</Link></li>
<li><Link to="/protected">Protected Page</Link></li>
</ul>
<Route path="/public" component={Public}/>
<Route path="/login" component={Login}/>
<PrivateRoute path='/protected' component={Protected} />
</div>
</Router>
)
}
HGowever, the problem is when I try to put the different scripts in different files and import them. From the above code, I moved the following code to a script named Authenticator.js, as below:
import React from 'react'
import { BrowserRouter as Route, Redirect } from "react-router-dom";
export const authenticator = {
isAuthenticated: false,
authenticate(cb) {
this.isAuthenticated = true
setTimeout(cb, 100) // fake async
},
signout(cb) {
this.isAuthenticated = false
setTimeout(cb, 100) // fake async
}
}
export const PrivateRoute = ({ component: Component, ...rest }) => (
<Route {...rest} render={(props) => (
authenticator.isAuthenticated === true
? <Component {...props} />
: <Redirect to={{
pathname: '/login',
state: { from: props.location }
}} />
)} />
)
and imported it in the original file as :
import { PrivateRoute, authenticator } from './login/Authenticator'
I also moved the Login class as a component to Login.js:
import React, { Component } from 'react'
import { authenticator } from './Authenticator'
import { Redirect } from "react-router-dom";
class Login extends Component {
state = {
redirectToReferrer: false
}
login = () => {
authenticator.authenticate(() => {
this.setState(() => ({
redirectToReferrer: true
}))
})
}
render() {
const { from } = this.props.location.state || { from: { pathname: '/' } }
const { redirectToReferrer } = this.state
if (redirectToReferrer === true) {
return <Redirect to={from} />
}
return (
<div>
<p>You must log in to view the page</p>
<button onClick={this.login}>Log in</button>
</div>
)
}
}
export default Login
And imported it in the script:
import Login from './login/Login'
And of course, I deleted these methods from the script from the tutorial. Ideally, now when, I go the /protected link, without logging in, I should be redirectd to the login page. HOwever, I do not see any thing. I can however access, the /login page and the login persists as expected. I believe the problem is with the Authenticator class, but I have not changed anything apart from moving the code to a different file.
Here is my final main script with the changes:
// import css
import 'bootstrap/dist/css/bootstrap.css'
import '#fortawesome/fontawesome-free/css/all.min.css'
import './css/ViewerApp.css'
// import js modules
import React, { Component } from 'react'
import { BrowserRouter as Router, Route, Link, withRouter } from "react-router-dom";
import 'jquery/dist/jquery.min.js'
import 'popper.js/dist/umd/popper.min.js'
import 'bootstrap/dist/js/bootstrap.min.js'
import Login from './login/Login'
import { PrivateRoute, authenticator } from './login/Authenticator'
// import TableView from './table/TableView'
const Public = () => <h3>Public</h3>
const Protected = () => <h3>Protected</h3>
class ViewerApp extends Component {
render() {
return (
<Router>
<ul style={{ marginTop:'122px' }}>
<li><Link to="/public">Public Page</Link></li>
<li><Link to="/protected">Protected Page</Link></li>
</ul>
<AuthButton/>
<Route path="/public" component={Public}/>
<Route path="/login" component={Login}/>
<PrivateRoute path='/protected' component={Protected} />
</Router>
)
}
}
const AuthButton = withRouter(({ history }) => (
authenticator.isAuthenticated ? (
<p>
Welcome! <button onClick={() => {
authenticator.signout(() => history.push('/'))
}}>Sign out</button>
</p>
) : (
<p>You are not logged in.</p>
)
))
export default ViewerApp;
Can anyone help? Thanks in advance.
It looks like you have wrong import in your authenticator file. You are importing the BrowserRouter instead of Route
import { BrowserRouter as Route, Redirect } from "react-router-dom";
This should be
import { Route, Redirect } from "react-router-dom";