I am following a tutorial to make a dropdown menu but I am stuck in the middle because instead of using the "props" keyword like The instructor did in the tutorial. I passed the props directly as arguments without props dot. When I wanted to implement {open && children} without props I got the Error that children are not defined
This is the tutorial I am following, And the minute when I get the Error https://youtu.be/IF6k0uZuypA?t=543
This is the NavItem.js component where I have the problem
import React, { useState, useEffect } from 'react';
function NavItem({ icon, title, ...props }) {
const [opened, setOpened] = useState(false);
return (
<li className='nav-item'>
<a
href='#'
target=''
className='icon-button'
onClick={() => setOpened(!open)}
>
{icon}
<div>{title}</div>
</a>
{open && children}
</li>
);
}
export default NavItem;
This is the Navbar.js Component where I call NavItem.js component
import React from 'react';
import NavItem from './NavItem';
import BellIcon from './icons/bell.svg';
import { ReactComponent as MessengerIcon } from './icons/messenger.svg';
import { ReactComponent as CaretIcon } from './icons/caret.svg';
import { ReactComponent as PlusIcon } from './icons/plus.svg';
import { ReactComponent as ChevronIcon } from './icons/chevron.svg';
function Navbar() {
return (
<>
<nav className='h-20 bg-[#242526] py-0 px-4 border-b border-[#474a4d] '>
<ul className='max-w-full h-full flex justify-end'>
<NavItem icon={<PlusIcon />} />
<NavItem icon={<BellIcon />} />
<NavItem icon={<MessengerIcon />} />
<NavItem icon={<CaretIcon />}>
{/* Here where to render The dropdown menu Items */}
</NavItem>
</ul>
</nav>
</>
);
}
export default Navbar;
I am using Tailwindcss for styling
Thank you for your help
You must either continue destruct props object:
({ icon, title, children, ...props })
Or access via props
{opened && props.children}
Related
the website i am trying to author, has 2 pages
page
route path
components
details
home
'/'
navbar,videgallery1,videogallery2,footer
concepts
'/concepts'
navbar,imggallery1,imggallery2,footer
Each page main component (video or image gallery) is twice for reason. its same but with different json content etc. (kind of category)
item
description
'/'
video gallery 1 (10 videos), video gallery 2(RealTime Section) (10 videos)
'/concepts'
image gallery 1(conceptart,50 images), image gallery 2 (Moodboards Section,40 images after concept art gallery)
Main Question
i am trying to add 'RealTime' link via react-scroll (in nav file). it works when i am on homepage ('/') route. But fails when i am on second page (/concepts). How to tell it to first go to '/' then try to scroll to element or component.?
same is case with 4th link (moodboards), it works from concept page but not from home page.
also please notice that 'Link' is from ReactScroll is disabled, as i was trying to test react-scroll.
if this can be acheived without react-scroll, that would be even better.
CODESANDBOX LINK
here you can see, realtime link working on main page but not working when you are in concepts page.
navbar.js
import React from "react";
import "./styles.css";
import { NavLink } from "react-router-dom";
// import { Link } from "react-router-dom";
import { Link, DirectLink, Element, Events, animateScroll as scroll, scrollSpy, scroller } from 'react-scroll'
import MyLogo from '../img/logo_ff2_2021.png';
export default function Nav(){
// navlinks can have a class of active, which can be styled, comparing to links
// classname, style, children, to, exact
return(
<div className="navbar">
<div className="logo">
<img src="assets/logo_ff2_2021.png" style={{width:'100%'}} alt="logo" />
</div>
<ul className="nav-links">
<NavLink style={({isActive}) => {return isActive ? {color: 'red'} : {}}} to="/">Home</NavLink>
<Link style={({isActive}) => {return isActive ? {color: 'red'} : {}}} to="RT" spy={true} smooth={true} duration={500}>RealTime</Link>
<NavLink style={({isActive}) => {return isActive ? {color: 'red'} : {}}} to="/concepts">Concepts</NavLink>
<Link style={({isActive}) => {return isActive ? {color: 'red'} : {}}} to="Moodboards" spy={true} smooth={true} duration={500}>Moodboards</Link>
</ul>
</div>
);
}
home.js
import headerVideo1 from '../assets/slide_rag.mp4';
import MyCarousel from '../components/Carousel';
import StickyFooter from '../components/Footer';
import VideoGallery from '../components/VideoGallery';
import VideoGallery2 from '../components/VideoGallery2';
import { DirectLink, Element, Events, animateScroll as scroll, scrollSpy, scroller } from 'react-scroll'
import './Home.css';
export function Home() {
// const videos = getVideos();
return (
<>
<MyCarousel />
<VideoGallery name="main" />
<Element name="RT" className="element">
<VideoGallery2 name="RT" />
</Element>
<StickyFooter />
</>
);
}
export default Home;
app.js
import React from 'react';
import './App.css';
import Nav from './components/Nav';
import { BrowserRouter , Route,Routes } from "react-router-dom";
import Home from './pages/Home';
import Concepts from './pages/Concepts';
import NotFound from './pages/NotFound';
function App() {
return (
<>
<BrowserRouter>
<div className="App">
<Nav />
</div>
<Routes>
<Route path="/" element={<Home/>} />
<Route path="/footer" component={<StickyFooter/>} />
<Route path="/concepts" element={<Concepts/>} />
<Route path="/about" element={<About/>} />
</Routes>
</BrowserRouter>
</>
);
}
export default App;
I'd suggest importing and using link components from react-router-hash-link. You set the id attribute on a DOM element on the page you are linking to, and use this hash target in the link.
Nav Example:
import React from "react";
import "./styles.css";
import { NavHashLink } from 'react-router-hash-link'; // <-- import link component
import MyLogo from "../img/logo_ff2_2021.png";
export default function Nav() {
return (
<div className="navbar">
<div className="logo">
<img
src="assets/logo_ff2_2021.png"
style={{ width: "100%" }}
alt="logo"
/>
</div>
<ul className="nav-links">
<NavHashLink // <-- render link component
style={({ isActive }) => {
return isActive ? { color: "red" } : {};
}}
to="/"
>
Home
</NavHashLink>
<NavHashLink
style={({ isActive }) => {
return isActive ? { color: "red" } : {};
}}
to="/#RT" // <-- pass route and hash to target
smooth
>
RealTime
</NavHashLink>
<NavHashLink
style={({ isActive }) => {
return isActive ? { color: "red" } : {};
}}
to="/concepts"
>
Concepts
</NavHashLink>
<NavHashLink
style={({ isActive }) => {
return isActive ? { color: "red" } : {};
}}
to="/concepts#Moodboards" // <-- pass route and hash to target
smooth
>
Moodboards
</NavHashLink>
</ul>
</div>
);
}
Home
export function Home() {
return (
<>
<VideoGallery name="main" />
<div id="RT" className="element"> // <-- wrapper div with "RT" id to target
<VideoGallery2 name="RT" />
</div>
</>
);
}
So I have this code wherein there's a button in the Header.jsx file that once clicked, it will display the content of the Notification.jsx file. The problem here is, I don't exactly know how can I display the content of Notification.jsx in index.js. I tried using conditional statements but to no avail and is it possible to hide the h1 element once the button is clicked?
Header.jsx
import React from "react";
import { Button } from "#mui/material";
import { IconButton } from "#mui/material";
import NotificationsIcon from "#mui/icons-material/Notifications";
import SearchIcon from "#mui/icons-material/Search";
import Menu from "#mui/material/Menu";
import MenuItem from "#mui/material/MenuItem";
import FullNotifList from "./FullNotifList"
export default function Header() {
const [anchorEl, setAnchorEl] = React.useState(null);
const open = Boolean(anchorEl);
const handleClick = (event) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
return (
<div>
<Button
id="basic-button"
aria-controls={open ? "basic-menu" : undefined}
aria-haspopup="true"
aria-expanded={open ? "true" : undefined}
onClick={handleClick}
>
<IconButton>
<NotificationsIcon />
</IconButton>
</Button>
<Menu
id="basic-menu"
anchorEl={anchorEl}
open={open}
onClose={handleClose}
MenuListProps={{
"aria-labelledby": "basic-button",
}}
>
{/* Button needs to be clicked in order to display Notification.jsx */}
<Button variant="contained">Notification Center</Button>
<MenuItem onClick={handleClose}>Profile</MenuItem>
<MenuItem onClick={handleClose}>My account</MenuItem>
<MenuItem onClick={handleClose}>Logout</MenuItem>
</Menu>
<IconButton>
<SearchIcon />
</IconButton>
</div>
);
}
Notification.jsx
import React from "react";
export default function Notification(){
return(
<div>
<ul>
<li> Hello </li>
<li> Hello </li>
<li> Hello </li>
<li> Hello </li>
</ul>
</div>
)
}
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import reportWebVitals from './reportWebVitals';
import Header from './Header'
import './index.css'
import Footer from './Footer';
import Notification from './Notification';
export default function Page(props) {
const [isClicked, setIsClicked] = React.useState(false)
function showHide(e) {
setIsClicked(true)
};
return(
<div className='main'>
<Header onClick={showHide}/>
{isClicked && <Notification />}
<h1> Sample body </h1>
<Footer />
</div>
)
}
ReactDOM.render(
<Page />,
document.getElementById('root')
);
Here is the sandbox link: https://codesandbox.io/s/friendly-darkness-9u5s22?file=/src/index.js
You were right to use conditional rendering, however your conditional logic isn't working because you're assuming your Header component has an event listener.
Events listeners are an important part of Javascripts history, but are more or less abstracted out with library's like Material UI. More on that in a minute, first let me present to you the quick and easy solution; in your index.js, utilize event listeners with vanilla html:
<div onClick={showHide}>
<Header />
{isClicked && <Notification />}
<h1> Sample body </h1>
<Footer />
</div>
You'll also want to use a boolean switch in cases like these:
function showHide(e) {
setIsClicked(!isClicked);
}
To listen to events, earlier versions used attachEvent:
element.attachEvent('onclick', function() { /* do stuff here*/ });
Modern browsers now support useEventListener:
element.addEventListener('click', function() { /* do stuff here*/ }, false);
Here you can attach event listeners to as many elements as you want (memory permitting), including the users window element. That final parameter is a relic of pre-universal Javascript browser support, so now capture events and bubbling events are both supported. The default (false) is set to bubbling, where events 'bubble up' the DOM tree from the target node. More information on that here.
You can target your event listeners in Header.jsx to handle your events manually, and learn a little about JS event propagation. Since this is React, we want to utilize the useEffect, and useCallback hook to stop infinite rendering. Then well pass the callback function as props, so you can 'interact' with the Header component from index.js:
<div className="main">
<Header callback={showHide} />
{isClicked && <Notification />}
<h1> Sample body </h1>
<Footer />
</div>
then in Header. jsx:
import { useCallback, useEffect } from "react";
export default function Header(props) {
const handleClick = useCallback((event) => {
props.callback(event);
}, [props]);
useEffect(() => {
window.addEventListener("click", handleClick);
}, [handleClick]);
...
Note that the window element will target the whole component. To add events to individual html elements with id="header-component", use:
let element = document.getElementById("header-component");
Now for the third and I'd say best solution, utilizing React's props design pattern. Header.jsx:
export default function Header(props) {
return(
<Button onClick={props.callback}>Display Notifications</Button> //here we use the MUI button, but you can also use div or any other event listening element
...
);
}
and same thing again in index.js:
<div className="main">
<Header callback={showHide} />
{isClicked && <Notification />}
<h1> Sample body </h1>
<Footer />
</div>
In this case, you can use different callback functions to attach as many events as you want to one element, while relying on React to do the heavy lifting.
Apologies for the basic question in advance, I'm not a strong frontend developer, and I have scoured the internet. I keep getting this error when I inspect my frontend app in chrome.
(3) Material-UI: The component prop provided to ButtonBase is
invalid. Please make sure the children prop is rendered in this custom
component.
Why are the social button tabs throwing this error?
Here is the code...
import React, {forwardRef} from 'react';
import '../../styles/header.css';
import {Link, useLocation} from 'react-router-dom';
import {Paper, Tabs, Tab} from '#material-ui/core';
import {Email, GitHub, LinkedIn} from '#material-ui/icons';
const Header: React.FC = () => {
const location = useLocation();
const renderSocialButton = (link: string, children: JSX.Element): JSX.Element => (
<a href={link}>
{children}
</a>
);
return (
<Paper square>
<Tabs
value={location.pathname}
indicatorColor='primary'
textColor='primary'
aria-label='menu tabs'
centered
>
<Tab
label='Home'
className={'tab_nav'}
component={Link}
to={'/'}
value={'/'}
/>
<Tab
label='About'
className={'tab_nav'}
component={Link}
to={'/about'}
value={'/about'}
/>
<Tab
label=''
className={'space_nav'}
disabled
/>
<Tab
component={ forwardRef(() =>
renderSocialButton('https://example.com', <Email className={'social_icon'} />)
)}
/>
<Tab
component={ forwardRef(() =>
renderSocialButton('https://example.com', <GitHub className={'social_icon'} />)
)}
/>
<Tab
component={ forwardRef(() =>
renderSocialButton('https://example.com', <LinkedIn className={'social_icon'} />)
)}
/>
</Tabs>
</Paper>
);
};
export default Header;
I think you're having problems because of the way that you're passing in a function inside of your component prop.
The Material UI docs suggest that you should "avoid inline functions and pass a static component to the component prop instead."
Ex. (from the docs):
const CustomLink = React.useMemo(
() =>
React.forwardRef((linkProps, ref) => (
<Link ref={ref} to={to} {...linkProps} />
)),
[to],
);
Then you could pass that inside of your component prop, rather than the function.
I am working on putting together a webpage with routing and I am having trouble getting redux to work. My goal is to send a GET response to the reducer but just to test the setup right now my goal is to send true. I can retrieve data from the redux store but I can't seem to send it and I am unsure where I might be going wrong. Here is what is supposed to happen:
Auth is checked in login or signup
App.js is wrapped in a provider
User can go to Cart.js and by clicking a button dispatch the value true
The can navigate to Menu.js and should be able to console.log the new value from the reducer
My problem: I can't seem to actually dispatch the true value. Nothing breaks but when I go to the Menu page, the console log shows the initial state of the reducer.
This has worked for me before in React Native. I'm wondering if I should be setting this up differently? or if authentication is messing things up?
Below is a sample of my code:
App.js
import React, { Component } from 'react';
import {
Route,
BrowserRouter as Router,
Switch,
Redirect,
} from "react-router-dom";
import Home from './pages/Home';
import Signup from './pages/Signup';
import Login from './pages/Login';
import Menus from './pages/Menus';
import Carts from './pages/Carts';
import Orders from './pages/Orders';
import Land from './pages/Land';
import { auth } from './services/firebase';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import ourReducer from './store/reducer';
const store = createStore(ourReducer);
global.api = 'https://pitapal.metis-data.site'
//global.api = 'http://localhost:3008';
function PrivateRoute({ component: Component, authenticated, ...rest }) {
return (
<Route
{...rest}
render={(props) => authenticated === true
? <Component {...props} />
: <Redirect to={{ pathname: '/login', state: { from: props.location } }} />}
/>
)
}
function PublicRoute({ component: Component, authenticated, ...rest }) {
return (
<Route
{...rest}
render={(props) => authenticated === false
? <Component {...props} />
: <Redirect to='/home' />}
/>
)
}
class App extends Component {
constructor() {
super();
this.state = {
authenticated: false,
loading: true,
};
}
componentDidMount() {
auth().onAuthStateChanged((user) => {
if (user) {
this.setState({
authenticated: true,
loading: false,
});
} else {
this.setState({
authenticated: false,
loading: false,
});
}
})
}
render() {
return this.state.loading === true ? <h2>Loading...</h2> : (
<Provider store={ store }>
<Router>
<Switch>
<Route exact path="/" component={Signup}></Route>
<PrivateRoute path="/home" authenticated={this.state.authenticated} component={Home}></PrivateRoute>
<PrivateRoute path="/menus" authenticated={this.state.authenticated} component={Menus}></PrivateRoute>
<PrivateRoute path="/carts" authenticated={this.state.authenticated} component={Carts}></PrivateRoute>
<PrivateRoute path="/order" authenticated={this.state.authenticated} component={Orders}></PrivateRoute>
<PublicRoute path="/signup" authenticated={this.state.authenticated} component={Signup}></PublicRoute>
<PublicRoute path="/login" authenticated={this.state.authenticated} component={Login}></PublicRoute>
</Switch>
</Router>
</Provider>
);
}
}
export default App;
Reducer.js
import { combineReducers } from 'redux';
const INITIAL_STATE = {
carts: 'nothing'
};
const ourReducer = (state = INITIAL_STATE, action) => {
const newState = { ...state };
switch (action.type) {
case "CARTS":
return {
...state,
carts: action.value
}
break;
}
return newState;
};
export default combineReducers({
reducer: ourReducer,
});
Carts.js
class Carts extends Component {
render() {
return (
<Container>
<Button onClick={()=>this.props.setCart(true)}>sendToRedux</Button>
</Container>
);
}
}
const mapStateToProps = (state) => {
const { reducer } = state
return { reducer }
};
const mapDispachToProps = dispatch => {
return {
setCart: (y) => dispatch({ type: "CARTS", value: y })
};
}
export default connect(mapStateToProps,
mapDispachToProps
)(Carts);
Menu.js
import React, { Component } from 'react';
import Header from "../components/Header";
import MenuItem from '../components/MenuItem';
import classes from './menus.module.css'
import { auth, db } from "../services/firebase";
import { Container, Col, Row } from 'react-bootstrap';
import { connect } from 'react-redux';
class Menu extends Component {
render() {
console.log('my carts data:', this.props.reducer.carts);
}
return (
<Container>
welcome to menu
</Container>
);
}
}
const mapStateToProps = (state) => {
const { reducer } = state
return { reducer }
};
export default connect(mapStateToProps)(Menu);
EDIT:
here is my screenshot from Redux Devtools, this means the dispatch is definitely being sent correct?
So it seems the issue is that when I navigate a page using my header component, state gets reloaded, the entire app is relaoded. Wondering if someone knows what it might be. Below is my header component:
Header.js
import { Link } from 'react-router-dom';
import { auth } from '../services/firebase';
//import "./header.css";
import React, { Component } from 'react'
import { Navbar, Nav, NavItem, NavDropdown, Form, FormControl, Button } from 'react-bootstrap'
// import {Link} from 'react-router-dom'
//import classes from './navbar.module.css';
import 'bootstrap/dist/css/bootstrap.min.css';
class Header extends Component {
render() {
return (
<div>
{auth().currentUser
?
<Navbar className="fixed-top" collapseOnSelect expand="lg" style={{ backgroundColor: '#485671' }} variant="dark">
<Navbar.Brand href="#home">PitaPal</Navbar.Brand>
<Navbar.Toggle aria-controls="responsive-navbar-nav" />
<Navbar.Collapse id="responsive-navbar-nav">
<Nav className="mr-auto">
<Nav.Link href="/login">Home</Nav.Link>
<Nav.Link href="/menus">Manage my Menus</Nav.Link>
</Nav>
<Nav>
<Button onClick={() => auth().signOut()} variant="outline-success">Sign Out</Button>
</Nav>
</Navbar.Collapse>
</Navbar>
:
<Navbar className="fixed-top" collapseOnSelect expand="lg" style={{ backgroundColor: '#485671' }} variant="dark">
<Navbar.Brand href="#home">PitaPal</Navbar.Brand>
<Navbar.Toggle aria-controls="responsive-navbar-nav" />
<Navbar.Collapse id="responsive-navbar-nav">
<Nav className="mr-auto">
<Nav.Link href="/login">Login</Nav.Link>
<Nav.Link href="/signup">Sign Up</Nav.Link>
</Nav>
<Nav>
<Nav.Link href="contact">Contact Us</Nav.Link>
</Nav>
</Navbar.Collapse>
</Navbar>
}
</div>
)
}
}
export default Header;
Issue
Your Header is using plain anchor tags to issue navigation to your route pages which has the side-effect of also doing a page load.
Solution
Use the react-router-dom Link component for linking.
Either specify the as prop of the Nav.Link or use Link
<Nav.Link as={Link} to="/login">Home</Nav.Link>
or
<Link to="/login">Home</Link>
class Header extends Component {
render() {
return (
<div>
{auth().currentUser
?
<Navbar className="fixed-top" collapseOnSelect expand="lg" style={{ backgroundColor: '#485671' }} variant="dark">
<Navbar.Brand href="#home">PitaPal</Navbar.Brand>
<Navbar.Toggle aria-controls="responsive-navbar-nav" />
<Navbar.Collapse id="responsive-navbar-nav">
<Nav className="mr-auto">
<Link to="/login">Home</Link>
<Link to="/menus">Manage my Menus</Link>
</Nav>
<Nav>
<Button onClick={() => auth().signOut()} variant="outline-success">Sign Out</Button>
</Nav>
</Navbar.Collapse>
</Navbar>
:
<Navbar className="fixed-top" collapseOnSelect expand="lg" style={{ backgroundColor: '#485671' }} variant="dark">
<Navbar.Brand href="#home">PitaPal</Navbar.Brand>
<Navbar.Toggle aria-controls="responsive-navbar-nav" />
<Navbar.Collapse id="responsive-navbar-nav">
<Nav className="mr-auto">
<Link to="/login">Login</Link>
<Link to="/signup">Sign Up</Link>
</Nav>
<Nav>
<Link to="contact">Contact Us</Link>
</Nav>
</Navbar.Collapse>
</Navbar>
}
</div>
)
}
}
So I am not sure if passing refs would be the best thing to do but it's kinda what I have set-out to do tell me if there is a better option..
So I am trying to have an onClick of a nav link, scroll down to the the div "contactForm".
App.js
import ContactForm from './components/ContactForm'
import ParllaxPage from './components/ParllaxPage'
import NavigationBar from './components/NavigationBar'
import React from 'react';
import './App.css';
const App = () => {
return (
< div cssClass="App" >
<body>
<span><NavigationBar /></span>
<ParllaxPage cssClass="parallax-wrapper" />
<ParllaxPage cssClass="parallax-wrapper parallax-pageOne" />
<ContactForm />
</body >
</div >
);
}
export default App;
I was trying to use forwardRef but I am not sure that I was doing it correctly so...
NavigationBar.js
import ContactForm from "./ContactForm";
import React, { useRef } from "react";
import App from "../App";
import { Nav, Navbar, Form, FormControl, Button } from "react-bootstrap";
const ContactFormRef = React.forwardRef((props, ref) => (
<ContactForm className="contactForm" ref={ref}>
{props.children}
</ContactForm>
));
const scrollToRef = (ref) => ref.current.scrollIntoView({ behavior: "smooth" });
const NavigationBar = () => {
const ref = React.forwardRef(ContactFormRef);
return (
<Navbar bg="light" expand="lg">
<Navbar.Brand href="#home">A1 Gutters</Navbar.Brand>
<Navbar.Toggle aria-controls="b casic-navbar-nav" />
<Nav className="mr-auto">
<Nav.Link href="#home">Home</Nav.Link>
<Nav.Link href="#link">Link</Nav.Link>
<Nav.Link href="#" onClick={console.log(ref)}>
Contact
</Nav.Link>
</Nav>
</Navbar>
);
};
export default NavigationBar;
I don't think the other files really need to be shown, I am just trying to get the className out of the ContactForm component so I can scroll to it onClick.. I currently just have a console.log in the onClick.
Using Hooks will simplify here.
Have state variable for gotoContact and ref for contactRef
Add click handler for navigation link contact
Add useEffect hook and when ever use click on contact and ref is available (value in ref.current) then call the scroll to view)
import ContactForm from "./components/ContactForm";
import ParllaxPage from "./components/ParllaxPage";
import React, { useState, useEffect, useRef } from "react";
import "./App.css";
const NavigationBar = ({ onClickContact }) => {
return (
<Navbar bg="light" expand="lg">
<Navbar.Brand href="#home">A1 Gutters</Navbar.Brand>
<Navbar.Toggle aria-controls="b casic-navbar-nav" />
<Nav className="mr-auto">
<Nav.Link href="#home">Home</Nav.Link>
<Nav.Link href="#link">Link</Nav.Link>
<Nav.Link href="#" onClick={() => onClickContact()}>
Contact
</Nav.Link>
</Nav>
</Navbar>
);
};
const App = () => {
const [gotoContact, setGotoContact] = useState(false);
const contactRef = useRef(null);
useEffect(() => {
if (gotoContact && contactRef.current) {
contactRef.current.scrollIntoView();
setGotoContact(false);
}
}, [gotoContact, contactRef.current]);
return (
<div cssClass="App">
<body>
<span>
<NavigationBar onClickContact={() => setGotoContact(true)} />
</span>
<ParllaxPage cssClass="parallax-wrapper" />
<ParllaxPage cssClass="parallax-wrapper parallax-pageOne" />
<div ref={contactRef}>
<ContactForm />
</div>
</body>
</div>
);
};
export default App;
You should identify the div "contactForm" with an id and have an anchor tag point to it:
<div id="contactForm"></div>
You can add scroll-behaviour: smooth to the body in CSS
No need to create a separate ContactFormRef wrapper. Simply use React.forwardRef in ContactForm itself. Those not passing a ref will not have to know it forwards refs.
Then, remember to further pass the ref received to a native element or use useImperativeHandle hook to add methods to it without passing it further down.
const ref = React.forwardRef(ContactFormRef)
This is wrong.
You should do it the same as with native components:
const ref = useRef()
return <ContactForm ref={ref} >
// etc
</ContactForm>
You are not rendering the ContactFormRef, so the reference points no nothing!
App.js should be like:
...
const App = () => {
const myNestedRefRef=React.useRef();
return (
...
<NavigationBar contactRef={myNestedRefRef}/>
...
<ContactForm ref={myNestedRefRef} />
...
);
}
...
ContactForm.js
...
function ContactForm=React.forwardRef((props, ref) => (
<form ref={ref}>
...
</form>
));
NavigationBar.js
const NavigationBar = ({contactRef}) => {
return (
...
<Nav.Link href="#" onClick={console.log(contactRef)}>
...
);
};
Consider that
If the <ContactForm/> hasn't been rendered yet, the ref will look like {current:null}