I'm trying to use the framer motion library to add an animation on component unmount but it's not working. I'm using the exit and initial prop values but there is no animation visible.
My app.tsx file:
import React, { useEffect, useState } from 'react';
import logo from './logo.svg';
import './App.css';
import Loader from './Components/Loader';
import { AnimatePresence, motion } from 'framer-motion';
const App: React.FC = () => {
const [loading, setLoading] = useState<boolean>(true);
useEffect(() => {
setTimeout(() => setLoading(false), 5000);
});
return (
<div className="App">
<AnimatePresence exitBeforeEnter>
{
loading ?
<Loader/>
:
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
</header>
}
</AnimatePresence>
</div>
);
};
export default App;
my loader component that I want to add the unmount animation to:
import { motion } from 'framer-motion';
import React from 'react';
import './style.css';
const Loader: React.FC = () => {
return (
<motion.div
initial={{ opacity: 1 }}
exit={{ opacity: 0 }}
>
<div className={'loader'}>
<h1>Loading...</h1>
<p>Some last minute bug fixes..</p>
</div>
</motion.div>
);
};
export default Loader;
From the docs:
Child motion components must each have a unique key prop so
AnimatePresence can track their presence in the tree.
Any string will work as long as it's unique:
<AnimatePresence exitBeforeEnter>
{
loading ?
<Loader key="loader"/>
:
<header className="App-header" key="header">
<img src={logo} className="App-logo" alt="logo" />
</header>
}
</AnimatePresence>
Related
When I add my Navigation component to my App.js file the entire site is blank. However, when I add my other components like my Header the page works completely fine. Am I missing something? There are no bugs or errors that are showing up either which is very confusing.
import { useState } from 'react'
import Navigation from './components/Navigation'
import Header from './components/Header';
import Collection from './components/Collection';
function App() {
const [count, setCount] = useState(0)
return (
<div>
<Navigation />
<Header />
<Collection />
</div>
)
}
export default App
import { useState } from "react";
import logo from "../icons/logo.svg";
import CSS from "../styles/Navigation.css";
import hamburger from "../icons/icon-hamburger.svg";
import hamburgerClose from "../icons/icon-close.svg";
import { MobileMenu } from "../components/MobileMenu";
function navigation() {
state = { clicked: false }
handleClick = () => {
this.setState({ clicked: !this.state.clicked })
}
return (
<>
<div className="navigation">
<img className="logo" src={logo} />
<button className="hamburger" onClick={this.handleClick}>
<img className={this.state.clicked ? {hamburger} : {hamburgerClose}}/>
</button>
<div className="navigation-menu">
<ul>
{MobileMenu.map((item, index) => {
return (
<li key={index}>
<a className={item.className} href={item.url}>
{item.title}
</a>
</li>
);
})}
</ul>
</div>
</div>
</>
);
}
export default navigation;
The state could only be used in class components. Using hooks, you can apply state to functional components too. Below code example
import React, { useState } from 'react';
function Example() {
// Declare a new state variable, which we'll call "count"
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
i am trying to setting up darkMode button, but i got this error ... Uncaught Error: Objects are not valid as a React child (found: object with keys {background, color}). If you meant to render a collection of children, use an array instead.
here is my data..................
my Contextjs component......
import { createContext, useReducer } from "react";
export const themeContext = createContext();
const initialState = {darkMode : true};
const themeReducer = (state, action) =>{
switch(action.type){
case'toggle':
return {darkMode : !state.darkMode};
default:
return state;
}
};
export const ThemeProvider = (props)=>{
const [state, dispatch] = useReducer (themeReducer, initialState);
return(
<themeContext.Provider value={{state, dispatch}}>
{props.children}
</themeContext.Provider>
);
};
my AppJs component.......
import Navbar from "./Components/Navbar/Navbar";
import "./App.css"
import { Intro } from "./Components/Intro/Intro";
import Services from "./Components/Services/Services";
import Experience from "./Components/Experience/Experience"
import Works from "./Components/Works/Works"
import Portfolio from "./Components/Portfolio/Portfolio"
import Testimonials from './Components/Testtimonials/Testimonials'
import Contact from "./Components/Contact/Contact"
import Footer from "./Components/Footer/Footer"
import {themeContext} from './Context'
import { useContext } from "react";
function App() {
const theme = useContext(themeContext);
const darkMode = theme.state.darkMode;
return (
<div className="App">
style={{
background : darkMode? 'black' : '',
color : darkMode? 'white' : ''
}}
<Navbar />
<Intro />
<Services />
<Experience />
<Works />
<Portfolio/>
<Testimonials/>
<Contact />
<Footer />
</div>
);
}
export default App;
and here is IndexJs..........
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import {ThemeProvider} from './Context';
ReactDOM.render(
<ThemeProvider>
<App />
</ThemeProvider>,
document.getElementById('root')
);
and error is:- Uncaught Error: Objects are not valid as a React child (found: object with keys {background, color}). If you meant to render a collection of children, use an array instead.
You have to pass style prop to component.
<div
className="App"
style={{
background: darkMode ? "black" : "",
color: darkMode ? "white" : "",
}}
>
I would rather prefer, create 2 classes dark and light and use like this:
<div className={`App ${darkMode ? "dark" : "light"}`}>
It's trying to render your style object as a child of the div, update it so it is an attribute of the div.
<div
className="App"
style={{
background: darkMode ? "black" : "",
color: darkMode ? "white" : "",
}}
>
<Navbar />
<Intro />
<Services />
<Experience />
<Works />
<Portfolio />
<Testimonials />
<Contact />
<Footer />
</div>
I added an onChange event to the Editor.js file, it sets the value of the value variable using setValue that causes rerender of the App component on every change. Values of both value and query are needed in Editor.js and Sidebar.js. Is there any better way to do this to improve the performance?
App.js Code:
import React, { Suspense, useState } from "react";
import "./assets/output.css";
import Footer from "./components/layouts/Footer";
import Navbar from "./components/layouts/Navbar";
import Sidebar from "./components/layouts/Sidebar";
import TableSection from "./components/table/TableSection";
const Editor = React.lazy(() => import("./components/editor/Editor"));
const App = () => {
const [query, setQuery] = useState("");
const [value, setValue] = useState("select * from customers");
return (
<div className="grid grid-cols-layout-desktop grid-rows-layout-desktop bg-gray-600 h-screen">
<Navbar />
<Sidebar setQuery={setQuery} setValue={setValue} />
<Suspense fallback={<div>Loading..</div>}>
<Editor setQuery={setQuery} value={value} setValue={setValue} />
</Suspense>
{query ? <TableSection query={query} /> : null}
<Footer />
</div>
);
};
export default App;
I have to clone a website using ReactJs which only works on desktop. When it is viewed in a mobile view or Tablet...it shows "SITE NOT AVAILABLE ON MOBILE". I want to do that too....but it is not working on my site
import "./App.css";
import Navbar from "./components/Navbar";
import Text from "./components/Text";
import Slider from "./components/Slider";
import Wallet from "./components/Wallet";
import Dropdown from "./components/Dropdown";
import MobileTablet from "./components/MobileTablet";
import { BrowserView, MobileView } from "react-device-detect";
import { BrowserRouter as Router } from "react-router-dom";
function App() {
return (
<>
<BrowserView>
<Router>
<Text />
<div className="box">
<Navbar />
<Dropdown />
<div className="box2">
<Slider />
</div>
</div>
<div className="box3">
<Wallet />
</div>
</Router>
</BrowserView>
<MobileView>
<MobileTablet />
</MobileView>
</>
);
}
export default App;
This is the code for App.js the main part....Can someone help me make my app responsive...since i am very new to this.
If you need any other codes pls let me know
you can use isMobile for conditional rendering
import {isMobile} from 'react-device-detect';
...
if (isMobile) {
return <MobileTablet />
}
``
Look, you can use a State to monitor the viewport of client window, then a useEffect to change it. The property window.innerWidth gives you the width of the client, and then you can specify it to work only under specific conditions:
import { useState, useEffect } from "react";
export default function App() {
const [userIsDesktop, setUserIsDesktop] = useState(true);
useEffect(() => {
window.innerWidth > 1280 ? setUserIsDesktop(true) : setUserIsDesktop(false);
}, [userIsDesktop]);
return (
<div className="App">
{userIsDesktop ? <h1>i'm a desktop</h1> : <h1>i'm a mobile</h1>}
</div>
);
}
I'm new to React and I'm currently setup my first project using Gatsby. Essentially I'm creating a website that use an API created with Strapi. So far, I would like to load the navbar items using an API call like that: http://localhost:3001/sections, where for sections, I mean the items of the navbar.
For doing so, I have defined an Index page like that:
import React from "react"
import Layout from "../components/layout/layout"
import SEO from "../components/layout/seo"
import BGTState from "../context/bgt/bgtState"
import "../styles/css/begreentannery.css"
const IndexPage = () => {
return (
<BGTState>
<Layout>
<SEO title="Home" />
</Layout>
</BGTState>
)
}
export default IndexPage
the BGTState contains the getSections() method that is used inside Layout:
import React, { useContext, useEffect } from "react"
import PropTypes from "prop-types"
import { injectIntl } from "gatsby-plugin-intl"
import BGTContext from "../../context/bgt/bgtContext"
import { Spinner } from "react-bootstrap"
import Footer from "./footer"
import SearchState from "../../context/search/SearchState"
import Search from "../../components/search"
import NavbarMobile from "../../components/layout/navbarMobile"
import NavbarDesktop from "../../components/layout/navbarDesktop"
const Layout = ({ children, intl }) => {
const bgtContext = useContext(BGTContext)
const { loading, getSections, sections } = bgtContext
useEffect(() => {
getSections()
//eslint-disable-next-line
}, [])
return !loading ? (
<>
<NavbarMobile sections={sections} />
<NavbarDesktop sections={sections} />
<SearchState>
<Search />
<div className="container-fluid">
<div className="main">
{children}
<Footer />
</div>
</div>
</SearchState>
</>
) : (
<div className="container" style={{ height: "100vh" }}>
<div className="row h-100 justify-content-center align-items-center">
<Spinner animation="grow" />
</div>
</div>
)
}
Layout.propTypes = {
children: PropTypes.node.isRequired,
}
export default injectIntl(Layout)
the problem is in the code above, essentially I call useEffect hook which grab the sections from the API. So, until the sections are downloaded, I stop the code like so:
return !loading ? (
this is the getSections() method inside BGTState:
const getSections = async () => {
try {
setLoading()
const res = await axios.get(
`${process.env.API_URL}/sections?_sort=order:ASC`
)
dispatch({
type: GET_SECTIONS,
payload: res.data,
})
} catch (err) {
dispatch({
type: GET_SECTIONS,
payload: err.response.msg,
})
}
}
in the Index page all works fine, but the problem is in the CollectionsPage, infact I have this structure:
import React from "react"
import { injectIntl } from "gatsby-plugin-intl"
import Layout from "../components/layout/layout"
import SEO from "../components/layout/seo"
import BGTState from "../context/bgt/bgtState"
import CollectionState from "../context/collection/collectionState"
import Collection from "../components/collection"
const CollectionsPage = ({ intl }) => {
return (
<BGTState>
<Layout>
<SEO
lang={intl.locale}
title={`${intl.formatMessage({ id: "collections" })}`}
/>
<CollectionState>
<Collection id={1} />
</CollectionState>
</Layout>
</BGTState>
)
}
export default injectIntl(CollectionsPage)
essentially, the component <CollectionState> isn't mounting 'cause in Layout there is the async call on getSections().
So in Collection component, I have:
import React, { useContext, useEffect } from "react"
import CollectionContext from "../context/collection/collectionContext"
import { Link } from "gatsby"
const Collection = ({ id }) => {
const collectionContext = useContext(CollectionContext)
const { loading, collection, getCollection } = collectionContext
useEffect(() => {
getCollection(id)
}, [])
if (loading) return React.Fragment
return (
<div className="container">
<div className="row">
{/*
<img
src={`${process.env.API_URL}${collection.feature_media.url}`}
className="w-100 mt-2 mb-2"
alt={""}
/>*/}
<Link to="#" className="bg-caption bg-no-underline">
fall/winter 20/21
</Link>
</div>
</div>
)
}
export default Collection
which generate that error:
and of course getCollection is not called and will generate other errors in the Collection component
How can I revisit this mechanism? Essentially I have to:
Load all the sections
Load all the components