react router v4 input component losing focus while typing - javascript

I'm using react router v4 and using the render prop to load up a settings component that has a dynamic input (a value prop based on the state with an onChange handler). When I load the component without using react router, typing into the input field is dynamic, and changes state as you type. But when I use react router, each character press re-renders the entire settings component, causing the input field to lose focus. Not sure why this is happening, since I'm using the render prop instead of the component prop on the <Route /> component. Any help would be appreciated!
My App Component:
import React, { Component, Fragment } from "react";
import { BrowserRouter, Route, Switch } from "react-router-dom";
import Home from "../Home/Home";
import Header from "../Header/Header";
import AppSettings from "../AppSettings/AppSettings";
import NotFound from "../NotFound/NotFound";
import { secsToMs, minsToMs, msToTime } from "../../helpers";
import "./App.css";
class App extends Component {
state = {
settings: {
time: {
break: minsToMs(5),
relax: minsToMs(15),
work: minsToMs(25)
},
trackLength: 2,
autoplay: true
},
defaultSettings: {
time: {
break: minsToMs(5),
relax: minsToMs(15),
work: minsToMs(25)
},
trackLength: 4,
autoplay: false
},
time: minsToMs(25),
totalTime: minsToMs(25),
timerPlaying: false,
track: {
tasksCompleted: 0,
breaksCompleted: 0,
timerName: "work"
}
};
updateSettings = (key, updatedSetting) => {
let settings = { ...this.state.settings };
settings.time[key] = updatedSetting;
this.setState({ settings });
};
//...other App methods
render() {
const MainAppContent = ({ location }) => (
<Fragment>
<Header track={this.state.track} location={location} />
<Home
timerPlaying={this.state.timerPlaying}
totalTime={this.state.totalTime}
time={this.state.time}
track={this.state.track}
trackLength={this.state.settings.trackLength}
startTimer={this.startTimer}
pauseTimer={this.pauseTimer}
resetTimer={this.resetTimer}
skipTimer={this.skipTimer}
/>
<AppSettings
settings={this.state.settings}
updateSettings={this.updateSettings}
restoreDefaultSettings={this.restoreDefaultSettings}
/>
</Fragment>
);
const SettingsAppContent = ({ location }) => (
<Fragment>
<Header track={this.state.track} location={location} />
<AppSettings
settings={this.state.settings}
updateSettings={this.updateSettings}
restoreDefaultSettings={this.restoreDefaultSettings}
/>
</Fragment>
);
return (
<main className="App">
<BrowserRouter>
<Switch>
<Route exact path="/" component={MainAppContent} />
<Route
path="/settings"
render={props => <SettingsAppContent {...props} />}
/>
<Route component={NotFound} />
</Switch>
</BrowserRouter>
</main>
);
}
}
export default App;
My AppSettings Component:
import React, { Component, Fragment } from "react";
import RangeSlider from "../RangeSlider/RangeSlider";
import { minsToMs } from "../../helpers";
import "./AppSettings.css";
class Settings extends Component {
render() {
return (
<Fragment>
<h1>Settings</h1>
{Object.keys(this.props.settings.time).map(key => (
<RangeSlider
name={key}
key={key}
time={this.props.settings.time[key]}
updateSettings={this.props.updateSettings}
/>
))}
<button onClick={this.props.restoreDefaultSettings}>
Revert to Default
</button>
</Fragment>
);
}
}
export default Settings;
My Input Component:
import React, { Component } from "react";
import { msToTime, minsToMs } from "../../helpers";
import "./RangeSlider.css";
class RangeSlider extends Component {
onSettingsChange = e => {
let rangeValue = parseInt(e.currentTarget.value);
if (rangeValue > 60) {
rangeValue = 60;
} else if (rangeValue < 1 || rangeValue === NaN) {
rangeValue = 1;
}
let rangeValueMs = minsToMs(rangeValue);
let key = e.currentTarget.name;
let updatedSetting = rangeValueMs;
const updatedSettings = {
...this.props.settings,
[key]: rangeValueMs
};
console.log("updatedSettings", updatedSettings);
this.props.updateSettings(key, updatedSetting);
};
render() {
const { name, time } = this.props;
return (
<div>
<input
type="number"
min="1"
max="60"
value={msToTime(time).m}
className="text-box"
name={name}
onChange={this.onSettingsChange}
/>
</div>
);
}
}
export default RangeSlider;

Related

Why is my component unable to access data from my reducer?

I am writing a React app in which somebody can sign up as a business or user, and a user is able to search for a business by name. I do not understand why I am getting an error when trying to render my search component, saying "TypeError: Cannot read properties of undefined (reading 'toLowerCase')". I do not understand why I am getting this error because I believe I am passing in the appropriate data via my reducers and the Redux store. This is my search component:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import BusinessCard from '../Business/BusinessCard'
import { Card } from 'semantic-ui-react';
class Businesses extends Component {
state = {newSearch: ""}
handleInputChange = e => {
this.setState({newSearch: e.target.value})
}
render() {
const { businessesReducer} = this.props;
let businessesMatch = businessesReducer.businesses.filter( (business ) => business.name.toLowerCase().includes(this.state.newSearch.toLowerCase()))
return (
<div>
<input placeholder="Search Events and Services Near You" value={this.state.newSearch} name="businessName" type="text" onChange={this.handleInputChange} />
<Card.Group itemsPerRow={3}>
{ businessesMatch.map((business, id) => <BusinessCard key={id} business={business} />)}
</Card.Group>
</div>
)
}
}
const mapStateToProps = (state) => {
return ({
businessesReducer: state.businessesReducer
})
}
export default connect(mapStateToProps)(Businesses);
My businesses reducer:
const initialState =
{
businesses:[],
isLoading: false
}
export default (state = initialState, action) => {
switch (action.type) {
case 'LOADING':
return {
...state,
isLoading: true
}
case "GET_ALL_BUSINESSES_SUCCESS":
return { ...state,
businesses: action.businesses,
isLoading: false
}
default:
return state
}
}
BusinessCard.js (which I am trying to render per the user's search)
import React, { Component } from 'react';
import { Card } from 'semantic-ui-react';
import { connect } from 'react-redux';
class BusinessCard extends Component {
constructor(props) {
super(props);
}
render(){
const { business, businessesReducer } = this.props;
return(
<Card>
<div key={business.id} >
<Card.Content>
<Card.Header><strong>{business.name}</strong></Card.Header>
</Card.Content>
</div>
</Card>
)
}
}
const mapStateToProps = state => {
return {
businesses: state.businesses,
businessesReducer: state.businessesReducer
}
}
export default connect(mapStateToProps)(BusinessCard);
And App.js
import { getAllBusinesses } from './actions/business/business';
import { BrowserRouter as Router, Route, Switch} from 'react-router-dom';
import history from './history';
class App extends React.Component {
componentDidMount() {
this.props.getAllBusinesses();
}
render() {
return (
<Router history={history}>
<div className="App">
<NavBar />
<Switch>
<Route exact path="/" component={Home}/>
<Route path="/about" component={About} />
<Route path="/services" component={Services} />
<Route path="/shop" component={Shop}/>
<Route path="/login-signup" component={LoginContainer}/>
<Route path="/signup" component={Signup}/>
<Route path="/business-signup" component={BusinessSignup}/>
<Route path="/professional-signup" component={ProfessionalSignup}/>
<Route path="/search" component={Businesses}/>
</Switch>
</div>
</Router>
)
}
}
const mapStateToProps = (state) => {
return {
businessesReducer: state.businessesReducer
}
}
export default connect(mapStateToProps, {getAllBusinesses})(App);
Does anybody have any idea why my search component cannot access "business" and its properties? Everything looks correct to me.
1: It would be good if you could show getAllBusinesses.
2: Please make sure if data exists in your store, you can use redux-dev-tools for that.
3: The first time that your component renders there is no data in your store and it's just an empty array so please first check if name exists and has value then try to convert it to lower case.
It would be something like this:
let businessesMatch = businessesReducer.businesses.filter(
(business) =>
business.name &&
business.name
.toLowerCase()
.includes(this.state.newSearch.toLowerCase())
);
Or if with optional chaining:
let businessesMatch = businessesReducer.businesses.filter((business) =>
business?.name
.toLowerCase()
.includes(this.state.newSearch.toLowerCase())
);
If none of these help please provide more information like a code sandbox.

React refresh component on login

I have 2 components, NavBar which contains a login modal and the 'body' of page.
I want to detect when a user logs in and re-render the page based on that. How do I update the login prop in the second component when I log in using the modal of the first one?
A simplified version of the code to keep it short:
// NavBar.js
export default class NavBar extends Component {
constructor(props) {
super(props)
this.initialState = {
username: "",
password: "",
loginModal: false
}
this.handleLogin = this.handleLogin.bind(this)
}
handleLogin(e) {
e.preventDefault()
loginAPI.then(result)
}
render() {
return( <nav> nav bar with links and login button </nav>)
}
// Some random page
export default class Checkout extends Component {
constructor(props) {
super(props);
this.state = {
order_type: 'none',
loggedIn: false
}
this.Auth = new AuthService()
}
componentDidMount() {
if (this.Auth.loggedIn()) {
const { username, email } = this.Auth.getProfile()
this.setState({ loggedIn: true, email: email })
}
try {
const { order_type } = this.props.location.state[0]
if (order_type) {
this.setState({ order_type: order_type })
}
} catch (error) {
console.log('No package selected')
}
}
componentDidUpdate(prevProps, prevState) {
console.log("this.props, prevState)
if (this.props.loggedIn !== prevProps.loggedIn) {
console.log('foo bar')
}
}
render() {
return (
<section id='checkout'>
User is {this.state.loggedIn ? 'Looged in' : 'logged out'}
</section>
)
}
}
// App.js
function App() {
return (
<div>
<NavBar />
<Routes /> // This contains routes.js
<Footer />
</div>
);
}
// routes.js
const Routes = () => (
<Switch>
<Route exact path="/" component={Home} />
<Route exact path="/register" component={Register} />
<Route exact path="/registersuccess" component={RegisterSuccess} />
<Route exact path="/faq" component={FAQ} />
<Route exact path="/checkout" component={Checkout} />
<Route exact path="/contact" component={Contact} />
{/* <PrivateRoute exact path="/dashboard" component={Dashboard} /> */}
<Route path="/(notfound|[\s\S]*)/" component={NotFound} />
</Switch>
)
I would recommend using the react context API to store information about the logged in user.
See: https://reactjs.org/docs/context.html
Example
auth-context.js
import React from 'react'
const AuthContext = React.createContext(null);
export default AuthContext
index.js
import React, { useState } from 'react'
import ReactDOM from 'react-dom'
import App from './App'
import AuthContext from './auth-context.js'
const AppWrapper = () => {
const [loggedIn, setLoggedIn] = useState(false)
return (
<AuthContext.Provider value={{ loggedIn, setLoggedIn }}>
<App />
</AuthContext.Provider>
)
}
ReactDOM.render(
<AppWrapper/>,
document.querySelector('#app')
)
Then inside any component you can import the AuthContext and use the Consumer component to check if the user is logged in order set the logged in state.
NavBar.js
import React from 'react'
import AuthContext from './auth-context.js'
const NavBar = () => (
<AuthContext.Consumer>
{({ loggedIn, setLoggedIn }) => (
<>
<h1>{loggedIn ? 'Welcome' : 'Log in'}</h1>
{!loggedIn && (
<button onClick={() => setLoggedIn(true)}>Login</button>
)}
</>
)}
</AuthContext.Consumer>
)
export default NavBar
HOC version
with-auth-props.js
import React from 'react'
import AuthContext from './auth-context'
const withAuthProps = (Component) => {
return (props) => (
<AuthContext.Consumer>
{({ loggedIn, setLoggedIn }) => (
<Component
loggedIn={loggedIn}
setLoggedIn={setLoggedIn}
{...props}
/>
)}
</AuthContext.Consumer>
)
}
export default withAuthProps
TestComponent.js
import React from 'react'
import withAuthProps from './with-auth-props'
const TestComponent = ({ loggedIn, setLoggedIn }) => (
<div>
<h1>{loggedIn ? 'Welcome' : 'Log in'}</h1>
{!loggedIn && (
<button onClick={() => setLoggedIn(true)}>Login</button>
)}
</div>
)
export default withAuthProps(TestComponent)
Alternatively if you have redux setup with react-redux then it will use the context API behind the scenes. So you can use the connect HOC to wrap map the logged in state to any component props.

React ReactCSSTransitionGroup with asyncComponent

I'm trying to load component asynchronicity with appropriate component base on the ReactCSSTransitionGroup package by this example: https://codesandbox.io/s/zkqlq2vo?from-embed
So I combined all to one component as the following:
import React, { Component } from 'react';
import ReactCSSTransitionGroup from 'react-addons-css-transition-group';
import './PageShell.less';
const PageShell = (importComponent) => {
return class extends Component {
state = {
component: null
}
componentDidMount() {
importComponent()
.then(cmd => {
this.setState({ component: cmd.default });
})
.catch({});
}
render() {
const C = this.state.component;
const component = C ? (<C {...this.props} />) : null;
return (
<ReactCSSTransitionGroup
transitionAppear={true}
transitionAppearTimeout={600}
transitionEnterTimeout={600}
transitionLeaveTimeout={200}
transitionName={`Slide${Math.random() >= 0.5 ? 'In' : 'Out'}`}>
{component}
</ReactCSSTransitionGroup>
);
}
};
};
export default PageShell;
And on my App.js:
import React, { Component } from 'react';
import Layout from './hoc/Layout/Layout';
import BurgerBuilder from './containers/BurgerBuilder/BurgerBuilder';
import Logout from './containers/Auth/Logout/Logout';
import AsyncComponent from './hoc/AsyncComponent/AsyncComponent';
const asyncCheckout = AsyncComponent(() => {
return import('./containers/Checkout/Checkout/Checkout');
});
const asyncOrders = AsyncComponent(() => {
return import('./containers/Orders/Orders');
});
const asyncAuth = AsyncComponent(() => {
return import('./containers/Auth/Auth/Auth');
});
class App extends Component {
render() {
let routes = (
<Switch>
<Route path="/auth" component={PageShell(asyncAuth)} />
<Route path="/" exact component={PageShell(BurgerBuilder)} />
<Redirect to="/" />
</Switch>
);
return (
<div>
<Layout>
{routes}
</Layout>
</div>
);
}
}
export default App;
For some reason that i don't understand, the transition in my upgraded PageShell component not working, like in the example from codesandbox, and i can't figure out why is that.

Change component place each route change

I want to change rendered component place each time the route (url) changes.
e.g. I have 3 blocks: Home, Works, Contacts. When url is site.com/home the content renders in Home block, when url is site.com/works the content moves to Works block and so on.
I did a kind of what I want but it renders the whole page when It seems more optimal to just moves new content.
So can you suggest better decisions?
The whole project you can get and run locally from here: https://github.com/g1un/reactjs-site
What it looks like (buggy regarding routing) you can see here: http://g1un.ru/reactjs/
I paste the main files below.
index.js
import React from 'react';
import { render } from "react-dom";
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import style from './../scss/style.scss';
import { Header } from './components/Header';
import { About } from './components/About';
import { Works } from './components/Works';
import { Contacts } from './components/Contacts';
import { NotFound } from './components/NotFound';
class App extends React.Component {
render() {
return (
<Router>
<div className="container">
<Switch>
<Route exact path="/" component={About}/>
<Route exact path="/works" component={Works}/>
<Route exact path="/contacts" component={Contacts}/>
<Route component={NotFound}/>
</Switch>
</div>
</Router>
);
}
}
render(<App />, window.document.getElementById('app'));
About.js (Works.js, Contacts.js are similar)
import React from 'react';
import DocumentTitle from 'react-document-title';
import { Header } from './Header';
export class About extends React.Component {
render() {
return (
<DocumentTitle title='About'>
<Header currentPath={this.props.location.pathname}>
<h1>
About
</h1>
</Header>
</DocumentTitle>
);
}
}
Header.js
import React from 'react';
const PATHS = ['/', '/works', '/contacts'];
const PAGES = ['About', 'Works', 'Contacts'];
import { HeaderItem } from './HeaderItem';
export class Header extends React.Component {
constructor(props) {
super();
this.currentPath = props.currentPath;
this.content = props.children;
this.paths = PATHS;
this.pages = PAGES;
}
render() {
return (
<header className="header">
<nav className="nav">
<div className="nav__list">
{this.paths.map((path, i) => {
return <HeaderItem key={i} currentPath={path} currentPage={this.pages[i]} pageContent={path === this.currentPath ? this.content : ''}/>;
})}
</div>
</nav>
</header>
);
}
}
HeaderItem.js
import React from 'react';
import { NavLink } from 'react-router-dom';
export class HeaderItem extends React.Component {
render() {
return (
<div className={"nav__item " + (this.props.pageContent ? "_active" : "")}>
<NavLink className="nav__link" exact activeClassName="_active" to={this.props.currentPath}>
{this.props.currentPage}
</NavLink>
{this.props.pageContent ? <div className="nav__content content">{this.props.pageContent}</div> : ''}
</div>
);
}
}
I've found the desicion myself.
The fact is that I can't use any blocks inside <Switch/>, so I've simply used <Route>s without <Switch/>, putting them in any blocks I need.
And for '404' page I've created <Switch/> block with same Routes inside without component attributes except one for '404' page.
Now in each HeaderItem I can control whether its content is visible or not.
New index.js:
import React from 'react';
import { render } from "react-dom";
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import DocumentTitle from 'react-document-title';
import style from './../scss/style.scss';
import { Header } from './components/Header';
import { HeaderItem } from './components/HeaderItem';
import { About } from './components/About';
import { Works } from './components/Works';
import { Contacts } from './components/Contacts';
import { NotFound } from './components/NotFound';
const PATHS = ['/', '/works', '/contacts'];
const PAGES = ['About', 'Works', 'Contacts'];
const COMPONENTS = [About, Works, Contacts];
class App extends React.Component {
constructor() {
super();
this.paths = PATHS;
this.pages = PAGES;
this.components = COMPONENTS;
this.state = {
documentTitle: this.getDocumentTitle()
};
}
updateDocumentTitle(pageTitle) {
if(this.state.documentTitle === pageTitle) return;
this.setState({
documentTitle: this.getDocumentTitle()
});
}
getDocumentTitle() {
let pathIndex = this.paths.indexOf(window.location.pathname);
if(pathIndex === -1) {
return 'Not found';
} else {
return this.pages[pathIndex];
}
}
render() {
return (
<DocumentTitle title={this.state.documentTitle}>
<Router>
<div className="container">
<Switch>
{this.paths.map((path, i) => {
return <Route key={i} exact path={path}/>;
})}
<Route render={() => <NotFound text="Error 404"/>}/>
</Switch>
<Header>
{this.paths.map((path, i) => {
return (
<HeaderItem
key={i}
routePath={path}
pageTitle={this.pages[i]}
updateDocumentTitle={this.updateDocumentTitle.bind(this)}
>
<Route exact path={path} component={this.components[i]}/>
</HeaderItem>
);
})}
</Header>
<Switch>
{this.paths.map((path, i) => {
return <Route key={i} exact path={path}/>;
})}
<Route render={() => <NotFound text="Page not found"/>}/>
</Switch>
</div>
</Router>
</DocumentTitle>
);
}
}
render(<App />, window.document.getElementById('app'));
New HeaderItem.js:
import React from 'react';
import { NavLink } from 'react-router-dom';
import { Content } from './Content';
import { About } from './About';
import { Works } from './Works';
import { Contacts } from './Contacts';
const COMPONENTS = [About, Works, Contacts];
const PAGES = ['About', 'Works', 'Contacts'];
export class HeaderItem extends React.Component {
constructor(props) {
super();
this.path = props.routePath;
this.content = props.children;
this.page = props.pageTitle;
this.components = COMPONENTS;
this.pages = PAGES;
this.index = this.pages.indexOf(this.page);
this.updateDocumentTitle = props.updateDocumentTitle;
this.state = {
isActive: this.path === window.location.pathname
};
}
componentWillUpdate() {
//to change page title if this component is active
if(this.path === window.location.pathname) {
this.updateDocumentTitle(this.page);
}
this.saveRouteComponent();
}
isActive() {
return this.path === window.location.pathname;
}
saveRouteComponent() {
if(this.state.isActive || this.path !== window.location.pathname) return;
//once opened route get 'isActive' state and its content will not removed when this route is deactivated
this.setState({ isActive: true });
}
render() {
return (
<div className={"nav__item " + (this.isActive() ? "_active" : "")}>
<div className="nav__item-wrapper">
<NavLink className="nav__link" exact activeClassName="_active" to={this.path}>
{this.page}
</NavLink>
</div>
{(this.isActive() || this.state.isActive) ? <div className="nav__content"><Content pageTitle={this.page}>{this.state.isActive ? React.createElement(this.components[this.index]) : this.content}</Content></div> : ''}
</div>
);
}
}

Why is react-transition-group not calling componentWillEnter nor componentWillLeave on route change?

I am following this hackernoon guide https://hackernoon.com/animated-page-transitions-with-react-router-4-reacttransitiongroup-and-animated-1ca17bd97a1a in order to apply enter and leave animations to my react components when a route changes. I have obviously adapted the code to fit my site, and have decided not to use Animated but rather just pure CSS. Right now I'm just testing the code with console.log statements, and I noticed that componentWillEnter and componentWillLeave are not being called on route changes. Also, componentWillAppear only gets called once.
Here is the relevant code for each component, including App.js and index.js:
Animated Wrapper:
import React, {Component} from "react";
import styles from '../styles/AnimatedWrapper.css';
const AnimatedWrapper = WrappedComponent =>
class AnimatedWrapper extends Component {
componentWillAppear(cb) {
console.log('componentWillAppear');
cb();
}
componentWillEnter(cb) {
console.log('componentWillEnter');
cb();
}
componentWillLeave(cb) {
console.log('componentWillLeave');
cb();
}
render() {
return (
<div id="animated-wrapper" className={styles.animatedPageWrapper}>
<WrappedComponent {...this.props}/>
</div>
);}
};
export default AnimatedWrapper;
App.js:
import React, { Component } from 'react';
import { Route, Switch } from 'react-router-dom';
import TransitionGroup from "react-transition-group/TransitionGroup";
import Navbar from "./components/Navbar";
import Footer from "./components/Footer";
import Slider from "./components/Slider";
import ComingSoon from "./components/ComingSoon";
const firstChild = props => {
const childrenArray = React.Children.toArray(props.children);
return childrenArray[0] || null;
}
class App extends Component {
render() {
return (
<div className="App">
<Navbar />
<Switch>
<Route
path="/coming-soon"
children={({ match, ...rest }) => (
<TransitionGroup component={firstChild}>
{match && <ComingSoon {...rest} />}
</TransitionGroup>
)}/>
<Route
path="/"
children={({ match, ...rest }) => (
<TransitionGroup component={firstChild}>
{match && <Slider {...rest} />}
</TransitionGroup>
)}/>
</Switch>
<Footer />
</div>
);
}
}
export default App;
index.js:
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
import App from './App';
import './index.css';
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById('root')
);
Slider.js:
import React, { Component } from 'react';
import _ from 'lodash';
// components
import AnimatedWrapper from './AnimatedWrapper';
import Separator from './Separator';
// styles
import styles from '../styles/Slider.css';
// images
import Apartment from "../../public/images/apartment.jpg";
import Floor from "../../public/images/floor.jpg";
import Furniture from "../../public/images/furniture.jpg";
import Kitchen1 from "../../public/images/kitchen.jpg";
import Kitchen2 from "../../public/images/kitchen-2.jpg";
class SliderComponent extends Component {
constructor(props) {
super(props);
this.state = {
currentSlide: 0,
slides: [Apartment, Floor, Furniture, Kitchen1, Kitchen2]
};
}
componentDidMount() {
this.zoomAnimation();
this.slideContentAnimation();
this.sliderInterval = setInterval(() => {
if (this.state.currentSlide === 4) {
if (this.refs.slider) {
this.setState({ currentSlide: 0 });
}
} else {
if (this.refs.slider) {
this.setState({ currentSlide: this.state.currentSlide + 1 });
}
}
}, 6000);
}
componentWillUpdate() {
const currentContent = document.getElementById(`content-${this.state.currentSlide}`);
setTimeout(() => {
currentContent.classList.remove(`${styles.currentContent}`);
}, 1500);
}
componentDidUpdate() {
this.zoomAnimation();
this.slideContentAnimation();
}
setSlide(number) {
this.setState({ currentSlide: number });
}
zoomAnimation() {
setTimeout(() => {
const currentSlide = document.getElementById(`slide-${this.state.currentSlide}`);
currentSlide.classList.add(`${styles.slideZoom}`);
}, 500);
}
slideContentAnimation() {
setTimeout(() => {
const currentContent = document.getElementById(`content-${this.state.currentSlide}`);
if (currentContent) {
currentContent.classList.add(`${styles.currentContent}`);
}
}, 1500);
}
renderSlides() {
return this.state.slides.map((slide, index) => {
const isCurrent = index === this.state.currentSlide;
const slideStyle = {
backgroundImage: `url(${this.state.slides[index]})`
}
return (
<div
id={`slide-${index}`}
key={`slide-${index}`}
className={`
${styles.slide}
${isCurrent ? styles.currentSlide : null}
`}
style={slideStyle}
alt="slide">
<div
id={`content-${index}`}
key={`content-${index}`}
className={`
${styles.content}
`}>
<h1>{`WE SPECIALIZE IN KITCHENS ${index}`}</h1>
<Separator
containerWidth={720}
circleWidth={5}
circleHeight={5}
backgroundColor="#fff"
lineWidth={350}
lineColor="#fff"
/>
<div
className={`${styles['hvr-sweep-to-top']} ${styles.btn}`}>
More Information
</div>
</div>
</div>
);
});
}
renderNavBar() {
return (
<div className={styles.sliderNav}>
{_.range(5).map((index) => {
return (
<div
key={index}
onClick={() => this.setSlide(index)}
className={this.state.currentSlide === index ? styles.current : null}>
</div>
)
})}
</div>
)
}
render() {
return (
<div className={styles.container} ref="slider">
<div className={styles.slidesContainer}>
{this.renderSlides()}
</div>
{this.renderNavBar()}
</div>
);
}
}
const Slider = AnimatedWrapper(SliderComponent);
export default Slider;
ComingSoon.js:
import React from 'react';
import AnimatedWrapper from './AnimatedWrapper';
import styles from '../styles/ComingSoon.css';
const ComingSoonComponent = function() {
return (
<div>
<div className={styles.mainContent}>
<div>
<h1 className={styles.mainTitle}>{`Coming Soon`}</h1>
</div>
</div>
</div>
);
};
const ComingSoon = AnimatedWrapper(ComingSoonComponent);
export default ComingSoon;
Try to Use react-transition-group, it will be help.
You can use it like this Example. As follow main code:
import { BrowserRouter, Route, Switch, Link } from 'react-router-dom'
import { CSSTransition, TransitionGroup } from 'react-transition-group'
const PageFade = (props) => (
<CSSTransition
{...props}
classNames="fadeTranslate"
timeout={1000}
mountOnEnter={true}
unmountOnExit={true}
/>
)
const Layout = ({ children }) => (
<section>
<nav>
<ul>
<li><Link to="/">Home</Link></li>
<li><Link to="/about">About</Link></li>
<li><Link to="/topics">Non existing</Link></li>
</ul>
</nav>
<hr />
{children}
</section>
)
const App = (props) => {
const locationKey = props.location.pathname
return (
<Layout>
<TransitionGroup>
<PageFade key={locationKey}>
<section className="fix-container">
<Switch location={props.location}>
<Route exact path="/" component={Home} />
<Route exact path="/about" component={About} />
<Route component={NotFound} />
</Switch>
</section>
</PageFade>
</TransitionGroup>
</Layout>
)
}
const BasicExample = () => (
<BrowserRouter>
<Route path="/" component={App} />
</BrowserRouter>
);
render(<BasicExample />, document.getElementById('root'));

Categories

Resources