how when loading a page to click on a button in react? - reactjs

how when loading a page to click on a button in react?
I need a button to be pressed when the page loads
https://codesandbox.io/s/gifted-poitras-3sknp
import ReactDOM from "react-dom";
import "./styles.css";
function App() {
return (
<div className="App">
<button onClick={() => alert("loaded")}>button</button>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Are you looking for something like this. Button clicks happens on page load and also when clicked on button?
class App extends React.Component {
constructor(){
super();
this.buttonClicked = this.buttonClicked.bind(this);
}
componentDidMount(){
this.buttonClicked();
}
buttonClicked(){
alert("I'm Clicked");
}
render() {
return (
<button onClick={() => this.buttonClicked()}>
button
</button>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>

use useRef to save a reference to the button element combined with useEffect to detect when the component mounts
import React, { useEffect, useRef } from "react";
function App() {
const buttonRef = useRef(null);
useEffect(() => {
buttonRef.current.click();
}, []);
return (
<div className="App">
<button ref={buttonRef} onClick={() => alert("button")}>
button
</button>
</div>
);
}

From React's Hooks API Reference
The function passed to useEffect will run after the render is committed to the screen.
So you can always consider to use useEffect to run whatever side effects do you want right after the page rendered. Make sure to pass [] as the second argument to make sure the arrow function will only be called once.
This is an alternative example of using the useEffect hook with document.getElementById(id) instead of useRef since that has already been mentioned
It is still better to use useRef especially if the component will be reusable in the same page.
import React, {useEffect} from "react";
useEffect(() => {
document.getElementById("btn").click();
},[]);
function App() {
return (
<div className="App">
<button id="btn" onClick={() => alert("loaded")}>button</button>
</div>
);
}

Related

React & Typescript Issue: trigger elements with InsertionObserver using props and manage them in other component

Small premise: I'm not a great Typescript expert
Hi everyone, I'm working on my personal site, I decided to develop it in Typescript to learn the language.
My component tree is composed, as usual, of App.tsx which render the sub-components, in this case Navbar.jsx and Home.jsx.
Below is the App.jsx code:
import './App.css';
import { BrowserRouter as Router, useRoutes } from 'react-router-dom';
import Home from './components/Home';
import Navbar from './components/Navbar';
import { useState } from 'react';
function App(){
const [navbarScroll,setNavbarScrool]=useState(Object)
const handleLocationChange = (navbarScroll : boolean) => {
setNavbarScrool(navbarScroll)
return navbarScroll
}
const AppRoutes = () => {
let routes = useRoutes([
{ path: "/", element: <Home handleLocationChange={handleLocationChange}/> },
{ path: "component2", element: <></> },
]);
return routes;
};
return (
<Router>
<Navbar navbarScroll={navbarScroll}/>
<AppRoutes/>
</Router>
);
}
export default App;
Here, instead, the Home.jsx code:
import { useInView } from 'react-intersection-observer';
import HomeCSS from "../styles/home.module.css"
import mePhoto from "../assets/me.png"
import { useEffect, useState } from 'react';
interface AppProps {
handleLocationChange: (values: any) => boolean;
}
export default function Home(props: AppProps){
const { ref: containerChange , inView: containerChangeIsVisible, entry} = useInView();
useEffect(()=>{
props.handleLocationChange(containerChangeIsVisible)
//returns false at first render as expected
console.log("Home "+containerChangeIsVisible)
},[])
return(
<>
<div className={`${ HomeCSS.container} ${containerChangeIsVisible? HomeCSS.container_variation: ''}`}>
<div className={HomeCSS.container__children}>
{/* when i scroll on the div the css change (this works)*/}
<h1 className={`${ HomeCSS.container__h1} ${containerChangeIsVisible? HomeCSS.container__h1_variation: ''}`}>My<br/> Name</h1>
<p>Computer Science student.</p>
</div>
<img src={mePhoto} className={HomeCSS.image_style}/>
</div>
<div ref={containerChange} style={{height:800,background:"orange"}}>
<p style={{marginTop:20}}>HIII</p>
</div>
</>
)
}
And Navbar.jsx:
import NavbarCSS from "../styles/navbar.module.css"
import acPhoto from "../assets/ac.png"
import { Link } from "react-router-dom";
import { useEffect, useState } from "react";
interface NavbarScroolProp{
navbarScroll:boolean
}
export default function Navbar(props:NavbarScroolProp){
const [scrollState,setScrollState]=useState(false)
const [pVisible,setpVisible] = useState('')
useEffect(()=>{
setTimeout(() => {
setpVisible("")
}, 3000)
setpVisible("100%")
},[])
//returns false also when should be true
console.log(props.navbarScroll)
return (
<>
{/*the props is undefined so the css doesn't change, i need to do this*/}
<nav className={`${props.navbarScroll?NavbarCSS.nav__variation:NavbarCSS.nav}`}>
<div className={NavbarCSS.nav_row}>
<div className={NavbarCSS.nav_row_container}>
<img src={acPhoto} className={NavbarCSS.image_style}/>
<p className={NavbarCSS.p_style} style={{maxWidth: pVisible}}>My name</p>
</div>
<div className={NavbarCSS.nav_row_tagcontainer}>
<Link className={NavbarCSS.nav_row_tag} to="/"> Home</Link>
<Link className={NavbarCSS.nav_row_tag} to="/"> About</Link>
<Link className={NavbarCSS.nav_row_tag} to="/"> Contact</Link>
</div>
</div>
</nav>
</>
);
}
In my application I want to change the background color whenever the div referring to the InsertionObserver ( I use "useInView" hook , from :https://github.com/thebuilder/react-intersection-observer) is displayed. The problem is that the div in question is in the Home.jsx component and I need to change the color of the divs in the navbar as well when the div in Home is triggered(or other components in case I need to in the future).
The question is: How can I dynamically trigger DOM elements of other components (to then perform certain operations) using the InsertionObserver ?
As you can see from the code I tried to create Props, but everything returns undefined and doesn't involve any changes.
I've tried without useEffect, without using the useInView hook, passing the object instead of the boolean value, but I can't find any solutions to this problem.
You would be of great help to me.
PS: I would like to leave the Navbar.jsx component where it is now, so that it is visible in all components.
Any advice or constructive criticism is welcome.

How to programatically create a Modal in React 18

I did a function that creates a modal programatically for React 17, where you just needed to call a function to create a new modal.
It was working fantastic before the ReactDOM.render was deprecated.
Is there a way to replace the render function with something else in React 18? Right now the createRoot function is only for the root component, I want to render simple components in a specified DOM element.
It worked like this:
app.jsx
<button onClick={() => createModal(<h1>I'm a component inside a modal</h1>)}>Open Modal</button>
It handles it's own state, very useful if you want to make a bunch of modals in seconds.
This is the code:
index.js => Here is the container.
import React from 'react'
import ReactDOM from 'react-dom'
import './index.scss'
import App from './App.jsx'
ReactDOM.render(
<React.StrictMode>
<div id="modal-container"></div> <- This is the container
<App />
</React.StrictMode>,
document.getElementById('root')
)
Modal/Modal.jsx => The modal component.
import { useState } from 'react'
import './Modal.scss'
const Modal = ({ content }) => {
const [isOpen, setIsOpen] = useState(true)
if (isOpen) {
return (<>
<div className="modal-background" onClick={() => setIsOpen(false)} />
<div className="modal-content" >
{content}
</div>
<button onClick={() => setIsOpen(false)} className="close-button" >Close</button>
</>)
} else return null
}
export default Modal
Modal/index.js => The call function:
import { render } from "react-dom"
import Modal from "./Modal"
const createModal = (content) => render(
<Modal key={Math.random()} content={content} />, document.getElementById("modal-container")
)
export default createModal
It worked using createRoot this way, instead of render:
Here is an example: CodeSandbox
Modal/index.js
import { createRoot } from 'react-dom/client'
import Modal from "./Modal"
const createModal = (content) => {
if (!window.modalContainer) {
window.modalContainer = createRoot(document.getElementById('modal-container'))
}
window.modalContainer.render(<Modal key={Math.random()} content={content} />)
}
export default createModal
It checks if createRoot on the specified component has been called before, so it only call createRoot once, and the render function any time a new modal is created.
If you have a better answer it would be awesome too. :)

document.getElementById() equivalent in React 2020

I have a component called Button.js that has a button that when clicked i simply would like to know if i am accessing the a div in another component called Timer.js. In vanilla javascript i would simply use document.getElementById() to capture the DOM node. How is this done in React?
I came across callback-refs in the docs but it isn't working. If using a ref isn't the React way of accessing DOM elements please refer me to the best way to do this. thanks in advance.
Button.js
function Button() {
const getHtml = () => {
const node = test.current;
console.log(node);
}
return (
<button onClick={getHtml}>GetHtml</button>
)
}
Timer.js
function Timer() {
const test = useRef(null);
return (
<div ref={test}>... </div>
<Button />
}
I would not use a reference to check if a component is rendered inside of another one.
You could get what you're looking for with createContext and useContext.
(It could work like you tried it. If you'd pass the ref to the button as a prop.)
With the context: You create a TimerContext.Provider in your Timer component and in your button you can check with useContext(TimerContext) if the expected key is in the object. If it's not there then the button is not inside of your Timer.
Please have a look at the snippet below or in the following Codesandbox.
//import React, { useContext, createContext } from "react";
//import "./styles.css";
const { useContext, createContext } = React;
const ContainerContext = createContext({
isInContainer: null
});
const Container = () => {
return (
<ContainerContext.Provider value={{ isInContainer: true }}>
<p>
In container:
<Button />
</p>
</ContainerContext.Provider>
);
};
const Button = () => {
const { isInContainer } = useContext(ContainerContext);
console.log(isInContainer);
const isInside = () => {
alert(isInContainer ? "clicked inside" : "not in container");
};
return <button onClick={isInside}>Click me</button>;
};
function App() {
return (
<div className="App">
<Container />
<Button />
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
rootElement
);
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<div id="root"></div>
Update 15.04.2020
The question was not clear to me at first but now I understand the use-case. The idea is to have an Editor component where you're writing markup that can be used to generate a copied snippet view and/or a html markup output.
For this the best is to use a reference to the Editor component and pass it as prop to the preview/output component - it would be also possible with a context but passing it is easier.
Like in the following Sandbox.

How to use React hooks to determine if sidebar should show?

I have read some introductions on React Hooks and want to make a simple app with a button in the header component, which determines if the main app should show the sidebar. The button sets the variable showSidebar in the header, and I want to read it again within my main component. The code for actually showing the sidebar is stripped out for brevity.
This is index.js:
import React, { useState } from "react";
import ReactDOM from "react-dom";
import Header from "./header";
import "./styles.css";
function App() {
const [showSidebar, setShowSidebar] = useState(true);
return (
<div className="App">
<Header />
<h1>Sidebar toggler</h1>
<p>
Should I show sidebar? <b>{showSidebar.toString()}</b>
</p>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
And this is the header.js:
import React, { useState } from "react";
export default function Header() {
const [showSideBar, setShowSidebar] = useState(true);
const toggleSidebar = () => setShowSidebar(!showSideBar);
return (
<header>
Button in header toggles sidebar:
<button onClick={() => toggleSidebar()}>
Toggle sidebar (state: {showSideBar.toString()})
</button>
</header>
);
}
I am new to React, but do not understand why the state does not update in index.js? I also made a CodeSandbox with the code.
useState is stores local state, for comparison you can think of it similar to setState in a class component (although in reality they aren't exactly equivalent). Therefore, setting setShowSidebar in App won't reflect the same value as that set in Header and vice versa.
It doesn't look like Header needs any form of local state if it's simply changing state of the outer component, you can pass in an event handler and any relevant state Header needs as props instead
index.js
function App() {
const [showSidebar, setShowSidebar] = useState(true);
const toggleSidebar = useCallback(() => setShowSidebar(value => !value));
return (
<div className="App">
<Header onClick={toggleSidebar} showSideBar={showSidebar} />
<h1>Sidebar toggler</h1>
<p>
Should I show sidebar? <b>{showSidebar.toString()}</b>
</p>
</div>
);
}
header.js
export default function Header(props) {
return (
<header>
Button in header toggles sidebar:
<button onClick={props.onClick}>
Toggle sidebar (state: {props.showSideBar.toString()})
</button>
</header>
);
}
What you're doing wrong is declaring a separate state in Header which you shouldn't do, because it has nothing to do with parent's state. Pass the parent state and a callback to update the parent state as a props to the header. Pass showSidebar as props to the Header component:
import React, { useState } from "react";
import ReactDOM from "react-dom";
import Header from "./header";
import "./styles.css";
function App() {
const [showSidebar, setShowSidebar] = useState(true);
return (
<div className="App">
// Pass prop here
<Header
showSidebar={showSidebar}
toggleSidebar={()=>{setShowSidebar(!showSidebar)}}
/>
<h1>Sidebar toggler</h1>
<p>
Should I show sidebar? <b>{showSidebar.toString()}</b>
</p>
</div>
);
}
// and then in your Header,
export default function Header(props) {
return (
<header>
Button in header toggles sidebar:
<button onClick={props.toggleSideBar}>
Toggle sidebar (state: {props.showSideBar.toString()})
</button>
</header>
);
}
You want to keep state showSidebar in the parent component (where you need to read it) and pass the functionality to change it to the header component (where you need to change showSidebar)
To do move toggleSidebar to index.js
const toggleSidebar = () => setShowSidebar(!showSideBar);
and pass the function to the Header component like this
<Header toggleSidebar={toggleSidebar} />
now invoke it on clickEvent in Header component like this
<button onClick={() => toggleSidebar()}>
remember to include the prop in your Header component
export default function Header({toggleSidebar}) {
You should have your toggleSidebar function in App.js itself, and pass toggleSidebar function and showSidebar state in Header component as props.
App.js
function App() {
const [showSidebar, setShowSidebar] = useState(true)
const toggleSidebar = () => setShowSidebar(!showSidebar)
return (
<div className="App">
<Header showSideBar={showSidebar} onClick={toggleSidebar} />
<h1>Sidebar toggler</h1>
<p>
Should I show sidebar? <b>{showSidebar.toString()}</b>
</p>
</div>
)
}
Header.js
import React from 'react'
export default function Header(props) {
return (
<header>
Button in header toggles sidebar:
<button onClick={props.onClick}>
Toggle sidebar (state: {props.showSideBar.toString()})
</button>
</header>
)
}
Demo

Link component or any other element with event listener is not firing the click event if the document has active eventListener too

When attaching 'click' event listener to the DOM, elements like Link or some buttons with onClick listener that are part of the ref are not reacting to the click event. If no action is taken - it works fine, but when I call for example toggleMenu() it just stops there.
Something you usualy see after applying e.stopPropagation() or e.preventDefault()...
Kinda weird don't know even how to explain, better just have a look on the code.
import React, { useRef, useEffect } from "react";
import ReactDOM from "react-dom";
import { BrowserRouter, Link } from "react-router-dom";
function App() {
const menuRef = useRef();
const onDocumentClick = ({ target }) => {
if (menuRef.current.contains(target)) {
// event stops here if any action is taken
// even an alert
// comment this line to see the difference
alert('This is not button\'s alert');
}
};
useEffect(() => {
document.addEventListener("mousedown", onDocumentClick);
return () => {
document.removeEventListener("mousedown", onDocumentClick);
};
}, []);
return (
<BrowserRouter>
<div ref={menuRef} className="App">
<Link to="/test">Not working</Link>
<p>Button should show an alert saying 'clicked'</p>
<button onClick={() => alert("clicked")}>Doesn't work</button>
</div>
<br/>
<br/>
<br/>
<p>Outside of 'ref'</p>
<Link to="/test">Works</Link>
<p>........................</p>
<button onClick={() => alert("clicked")}>Works</button>
</BrowserRouter>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
I have the code on https://codesandbox.io/s/24z2v670wr if you'd like to test it out.
Solved. Should be click instead of mousedown
details here. https://github.com/facebook/react/issues/15455

Resources