How can I use window.scrollby with react? - css

I am trying to click a button which scrolls down to a specific portion of my app. So currently I have:
class Nav extends Component {
foo(){
console.log('baz')
window.scrollTo(0, 100);
}
render() {
return (
<nav>
<a href="#" onClick={()=> this.foo()}>About</a>
</nav>
);
}
}
This will console.log "baz" but won't scroll down to 100

Remove the
href="#"
This is causing the link to link the top of the page

You can do like this -
const handleRef = (param) => window.scrollTo(0, param);
<p onClick={()=> handleRef(1000)} >Drops</p>

import react from "react";
const Stchange = ()=>{
const dev = ()=>{
window.scrollBy(0,50);
}
return(
<>
<button onClick={dev}>Scroll</button>
<h1>There are man struc Lorem Ipsum which looks reasonable. The</h1>
</>
)
}
export default Stchange;

We have to prevent the default action of the anchor tag using event.preventDefault() method and change href="#" to href="/" in anchor tag
class Nav extends Component {
foo(event){
event.preventDefault();
console.log('baz')
window.scrollTo(0, 100);
}
render() {
return (
<nav>
<a href="/" onClick={(event)=> this.foo(event)}>About</a>
</nav>
);
}
}

Related

How to add a class on click, and remove the same class from all other elements?

I have a button navigation and when you click on a button, the active class is added. My goal is for the active class to be added to the button clicked, but remove that class of active on all other buttons if present. The 'About' button will have a class of active on page load.
Not sure how to translate this to React, in JavaScript on click I would remove the class from all the elements in a loop and add a class to the target clicked if it did not already have the active class.
Code Sandbox - https://codesandbox.io/s/toggle-active-on-class-clicked-remove-from-the-rest-r467l1?file=/src/App.js
export default function Header() {
const [active, setActive] = useState(true);
const toggleColor = function (e) {
// on load, 'About' button has active class
// when clicking another menu item add active class, remove active from the rest of buttons
console.log(e.target);
};
return (
<header className="header-img-container">
<nav>
<ul>
<li>
<button onClick={toggleColor} className={active ? "active" : ""}>
About
</button>
</li>
<li>
<button onClick={toggleColor}>Skills</button>
</li>
<li>
<button onClick={toggleColor}>Projects</button>
</li>
<li>
<button onClick={toggleColor}>Words</button>
</li>
</ul>
</nav>
</header>
);
}
There are so many ways to solve that problem. You can try this if it's meet your requirements.
import "./styles.css";
import { useState } from "react";
const list = ["About", "Skills", "Projects", "Words"];
export default function Header() {
const [activeLink, setActiveLink] = useState("About");
return (
<header className="header-img-container">
<nav>
<ul>
{list.map((item) => (
<li key={item}>
<button
onClick={() => setActiveLink(item)}
className={activeLink === item ? "active" : ""}
>
{item}
</button>
</li>
))}
</ul>
</nav>
</header>
);
}
Create a state like this
const [active, setActive] = useState({About: true, Skills: false, Projects: false, Words: false})
А change local parameter to add a class to element. For example
<li>
<button onClick={() => {
setActive({...active, About: false, Skills: true, Projects: false,
Words: false })
}}>Skills</button>
</li>
There are many possible approaches, here is a basic example that uses an object type active state to store the value for each list item.
const [active, setActive] = useState({ About: true })
The list data is stored in an array so it can be mapped in the JSX part of the component.
const itemList = ["About", "Skills", "Projects", "Words"]
While index is not an ideal key it is used here just for example purpose.
{
itemList.map((item, index) => (
<li key={index}>
<button
onClick={() => toggleColor(item)}
className={active[item] ? "active" : ""}
>
{item}
</button>
</li>
));
}
toggleColor sets value for active, and it specify that active should always be in the format of {About: true}, {Skills: true} and such. The !!! covers the case when certain keys are not existing in the object.
const toggleColor = function (item) {
setActive((prev) => {
return { [item]: !!!prev[item] };
});
};
Below is the full example, it runs in the snippet for convenience.
function Header() {
const [active, setActive] = React.useState({ About: true });
const itemList = ["About", "Skills", "Projects", "Words"];
const toggleColor = function (item) {
// on load, 'About' button has active class
// when clicking another menu item add active class, remove active from the rest of buttons
setActive((prev) => {
return { [item]: !!!prev[item] };
});
};
return (
<header className="header-img-container">
<nav>
<ul>
{itemList.map((item, index) => (
<li key={index}>
<button
onClick={() => toggleColor(item)}
className={active[item] ? "active" : ""}
>
{item}
</button>
</li>
))}
</ul>
</nav>
</header>
);
}
const App = () => {
return (
<div>
<Header />
</div>
);
};
ReactDOM.render(<App />, document.querySelector("#root"));
.App {
font-family: sans-serif;
text-align: center;
}
button {
padding: 6px;
}
.active {
border: 1px solid pink;
color: hotpink;
}
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.1.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.1.0/umd/react-dom.production.min.js"></script>

Using localStorage to keep css style in react after page reload

I would like to use localStorage to store a css style :focus for my elements. Currently when I click on component in my Dropdown it toggles green color, but when I click outside of it or I reload page, it disappears. Check the screenshot below.
How I can implement here localStorage to save :focus after page reload or maybe there is even better way of doing that which I don't know?
My Menu
const DropdownMenu = (props) => {
let companyElements = props.state.companies.map(c => (
<DropdownItem key={c.id} name={c.name} owner={c.owner} id={c.id} /> ));
return (
<div className="dropdown">
{companyElements}
</div>
);
}
My Item
const NavItem = (props) => {
const [open, setOpen] = useState(false);
return (
<div>
<li className="nav-item">
<a href="#" className="icon-button"
onClick={() => setOpen(!open)}>
{props.state.companies[0].name}
</a>
{open && props.children}
</li>
</div>
);
}
Style
.menu-item:focus{
background-color: green;
}

How to catch click event with addEventListener

I am having a modal with button inside. Unfortunatly, it's not properly working. During the build I got an error : TypeError: Cannot read property 'addEventListener' of null
Below is the code:
import React from "react";
import { Modal } from "react-bootstrap";
import '../../assets/styles/Login.css';
class LoginRegisterModal extends React.Component {
constructor(props, context) {
super(props);
this.state = {show: false};
}
componentDidMount(){
const signUpButton = document.getElementById('signUp');
const signInButton = document.getElementById('signIn');
const container = document.getElementById('container');
signUpButton.addEventListener('click', () => {
container.classList.add('right-panel-active');
});
signInButton.addEventListener('click', () => {
container.classList.remove('right-panel-active');
});
}
....
render() {
const styleModal = {
marginTop: "15%",
marginLeft: "30%",
padding: 0,
width:770,
height:480,
backgroundColor:"#ffffffff",
borderRadius:21.5,
}
return (
<Modal show={this.state.show} style={styleModal} >
<div class="container" id="container">
<div>
.....
</div>
<div class="overlay-container">
<div class="overlay">
<div class="overlay-panel overlay-left">
<h1>Sign in.</h1>
<p>
Nice to see you again.Login and continue the journey.
</p>
<button class="ghost" id="signIn">Sign In</button>
</div>
<div class="overlay-panel overlay-right">
<h1>Hey, new friend!</h1>
<p>New to the Village? Sign up and start your journey</p>
<button class="ghost" id="signUp">Sign Up</button>
</div>
</div>
</div>
</div>
</Modal>
);
}
}
export default LoginRegisterModal;
I have tried adding a if condition before the addListener but it's just fixing the error but not working.
Also I have tried to replace by onClick instead but it's not working the code
signUpButton = () => {
container.classList.add('right-panel-active');
}
but container is not known..
Any idea?
Thanks
Your code should be inside component did mount method componentDidMount(). That's because when you look for a element with id "signUp" it doesn't exist yet. I don't encourage you to do what you are doing. A better approach would be <button onClick={myMethod}>

How do I scroll up and down a SideBar rather than the whole window?

I will only show relevant code as there is a lot of it. This is the parent component App:
export default class App extends React.Component {
render() {
return (
<nav className="navbar navbar-expand-xl navbar-side" aria-label="Side Navigation">
<div className={`navbar-toggler ${this.state.notification ? 'has-notification' : ''}`} data-toggle="collapse" data-target="#sidebarCollapse" aria-controls="sidebarCollapse" aria-expanded="false" aria-label="Toggle side navigation">
Menu
</div>
<div className="collapse navbar-collapse" id="sidebarCollapse">
<ul className="navbar-nav mr-auto">
<li className="nav-user">
<div className="profile-pic">
<i className="fa fa-lg fa-user mt-1" />
</div>
<i><span>{this.state.authenticatedUser.first_name} {this.state.authenticatedUser.last_name}</span><br />{this.state.authenticatedUser.job_title}</i>
</li>
<NavBar />
</ul>
</div>
</nav>
)
}
This is the Navbar component:
class NavBar extends Component {
constructor(props) {
super(props);
this.state = {
auth: false,
slide: 0, // How much should the Navbar slide up or down
lastScrollY: 0, // Keep track of current position in state
}
}
componentWillMount() {
let navbar = document.getElementById('navbar-div');
navbar.addEventListener('scroll', this.handleScroll);
}
componentWillUnmount() {
let navbar = document.getElementById('navbar-div');
navbar.removeEventListener('scroll', this.handleScroll);
}
handleScroll = () => {
let navbar = document.getElementById('navbar-div');
const { lastScrollY } = this.state;
const currentScrollY = navbar.scrollY;
if (currentScrollY > lastScrollY) {
this.setState({ slide: '-48px' });
} else {
this.setState({ slide: '0px' });
}
this.setState({ lastScrollY: currentScrollY });
};
render() {
return (
<div className="navbar-div" id="navbar-div">
{this.adminMenu()}
{this.usersMenu()}
</div>
);
}
}
adminMenu and usersMenu are just arrays of objects which output the object names. The error I get says navbar is null hence it cannot add an event listener onto a null object. How do I solve this?
Use componentDidMount rather than componentWillMount. The latter will run before any markup is rendered.
You can read more about lifecycle methods here: https://reactjs.org/docs/state-and-lifecycle.html#adding-lifecycle-methods-to-a-class
However, I'd highly recommend you to apply a handler on the element instead of componentDid/Will/Mount/Unmount, like this:
render() {
return (
<div className="navbar-div" id="navbar-div" onScroll={this.handleScroll}>
{this.adminMenu()}
{this.usersMenu()}
</div>
);
}

React Modals visible for a split-second on page load

I am rendering modals in React.
My index.html looks like this:
<div id="root"></div>
<div id="modal"></div>
And all my modals are rendered (through a portal) as a child of .modal.
Each modal element has the following form:
<div class="modal-background open">
<!-- children -->
</div>
Where the class can be modal-background open or modal-background closed. The entire component is:
interface OwnProps {
children: React.ReactNode
isOpen: boolean
onExit: () => void
}
export class Modal extends React.Component<OwnProps, any> {
_exit = () => this.props.onExit();
_renderModal = () => (
<div className={`modal-background ${this.props.isOpen ? "open" : "closed"}`} onClick={this._exit}>
{this.props.children}
</div>
);
render() {
if (this.props.isOpen) {
document.body.className += " no-scroll";
} else {
document.body.classList.remove("no-scroll");
}
let elem = document.querySelector("#modal");
if (elem == null) {
console.log("Could not render modal.");
return null;
}
return ReactDOM.createPortal(this._renderModal(), elem);
}
}
And the CSS looks like:
.modal-background {
/* Other styling - this a dark backdrop for a modal child */
background-color: rgba(0,0,0,0.2);
transition: opacity 150ms ease-out;
&.closed {
opacity: 0;
pointer-events: none;
}
&.open {
pointer-events: all;
opacity: 1;
&:hover {
cursor: pointer;
}
}
}
So my modal is used like <Modal><CustomModalElement/></Modal>.
When I load the page, my modal elements briefly flash, indicating that they are not hidden on load (but a split-second afterwards).
I can fix this by adding display: none and display: inherit into the css, but then I miss the nice transitions.
Is there a better way to do this?
Not sure you need to do anything else inside your index.html file except
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<div id="modal"></div>
And for your Modal.js, you could try something along these lines:
import React from "react";
import ReactDOM from "react-dom";
const Modal = props => {
return ReactDOM.createPortal(
<div className="ui dimmer modals visible active">
<div className="ui standard modal visible active">
<div className="header">Delete Object</div>
<div className="content">
Are you sure you want to delete this?
</div>
<div className="actions">
<button className="ui primary button">Delete</button>
<button className="ui button">Cancel</button>
</div>
</div>
</div>,
document.querySelector("#modal")
);
};
export default Modal;
and then inside your other component where the user will execute the modal:
import React from "react";
import Modal from "../Modal"; // or wherever your Modal is in the file tree
const ObjectDelete = () => {
return (
<div>
ObjectDelete
<Modal />
</div>
);
};
export default ObjectDelete;
Keep in mind that the example of modal I offer here is not a reusable component.

Resources