i have this problem that 'paragraphText' and 'paragraphLinkText' don't render.
I'm learning so i will be thankful for an explanation.
export default function Modal({open, onClose}, props)
If i change positions of {open, onClose} and props then the methods don't work so it's probably that but i have no idea why.
console.log(open) console.log(props) :
true,
Object { }
import React, {useState} from 'react'
import './css/header.css'
import Modal from './Modal'
export default function Header(){
const [isOpen, setIsOpen] = useState(false)
return(
<div className='header'>
<div className='Sign In'><h1 onClick={() => setIsOpen(true)}>Sign In</h1></div>
<Modal open={isOpen} onClose={() => setIsOpen(false)} paragraphText="Already have an account?" paragraphLinkText="log in"></Modal>
</div>
)
}
import React from 'react'
import ReactDom from 'react-dom'
// import classes
import SignIn from './SignIn'
// import css
import './css/modal.css'
// import rest
import { FaTimes } from 'react-icons/fa'
import { IconContext } from "react-icons";
export default function Modal({open, onClose}, props){
console.log(open)
console.log(props)
if(!open) {return null}
return ReactDom.createPortal(
<div className='modal-overlay'>
<div className="modal-inside" id="modal-signin">
<div className="close-modal-box-top">
<IconContext.Provider value={{size:"1em", style: { verticalAlign: 'bottom' } }}>
<div className="close-modal" onClick={onClose}><FaTimes /></div>
</IconContext.Provider>
<h2>sign in</h2>
<div></div>
</div>
<SignIn />
<button>submit</button>
<div className='loginP'><p>{props.paragraphText}</p><p>{props.paragraphLinkText}</p></div>
</div>
</div>,
document.getElementById("portal")
)
}
The problem has to do with destructuring and no necessarily with React in the following line:
export default function Modal({open, onClose}, props){
you are receiving two parameters {open, onClose} and props.
React component received all the props in the first parameters therefore if you want to get props in the second parameter there will never be there.
The solution is to spread the rest of the props so you can grab everything else that has been pass down from the top:
export default function Modal({open, onClose, ...props}){
then you will have access to all the props that have been pass down from the top component.
An alternative method for the previous solution you can do:
export default function Modal(props){
const {open, onClose, paragraphText, paragraphLinkText} = props;
}
which I consider is more readable.
Add a comment if you have questions about this explanation.
Related
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.
I have a simple react page so far where I just have a home component which seems to work fine it is made up from the code I have included what I am trying to do is to render another component the main component when the button that is part of the home component is clicked but it keeps giving me the error and I have no idea what I am doing wrong in this case I have included code for all of my files the main component isn't fully finished right now it was just to test what I am currently doing that I added a paragraph placeholder any help is appreciated thanks
Error: Unknown error
(/node_modules/react-dom/cjs/react-dom.development.js:3994) !The above
error occurred in the component: at Main (exe1.bundle.js:94:3)
at div at App (exe1.bundle.js:31:52) Consider adding an error boundary
to your tree to customize error handling behavior. Visit
https://reactjs.org/link/error-boundaries to learn more about error
boundaries. !Error: Unknown error
Home Component:
import React from "react";
export default function Home(props) {
return (
<main className="home-main">
<div className="content-container">
<div className="bottom-corner">
</div>
<div className="top-corner">
</div>
<h1 className="home-heading">Quizzical</h1>
<p className="home-description">Some description if needed</p>
<button
className="start-button"
onClick={props.handleClick}
>Start quiz
</button>
</div>
</main>
)
}
Main Component:
import react from "react";
export default function Main() {
return (
<h1>hello </h1>
)
}
App:
import React from "react";
import Main from "./components/Main"
import Home from "./components/Home"
export default function App() {
const [startQuiz, setStartQuiz] = React.useState(false);
function clickStart() {
// flip the state on each click of the button
console.log(startQuiz);
setStartQuiz(prevState => !prevState);
}
return (
<div>
{console.log("start", startQuiz)}
{startQuiz ?
<Main />
:
<Home handleClick={clickStart}/> }
}
</div>
)
}
Index:
import React from "react"
import ReactDOM from "react-dom"
import App from "./App";
ReactDOM.render(<App />, document.getElementById("root"))
I think you just have a typo here
import react from "react";
should be
import React from "react";
You can try changing your setStartQuiz to just simply negate the current startQuiz value instead of using prevState.
function clickStart() {
// flip the state on each click of the button
console.log(startQuiz);
setStartQuiz(!startQuiz);
}
Here's a working example based on your code.
code sandbox
import React, { useState } from "react";
const Main = () => <h1>hello </h1>;
const Home = (props) => {
return (
<main className="home-main">
<div className="content-container">
<div className="bottom-corner"></div>
<div className="top-corner"></div>
<h1 className="home-heading">Quizzical</h1>
<p className="home-description">Some description if needed</p>
<button className="start-button" onClick={props.handleClick}>
Start quiz
</button>
</div>
</main>
);
};
export default function App() {
const [startQuiz, setStartQuiz] = useState(false);
return (
<div>
{startQuiz && <Main />}
{!startQuiz && <Home handleClick={() => setStartQuiz(true)} />}
</div>
);
}
I have this component "Board", there's other 3 components: TopBar, SandToHide and TreasureBoxes.
I just want that the TopBar component reads the "money" value and the TreasureBoxes executes the increment of money. The TopBar is reading the value that i'm setting in Board, but the TreasureBoxes doesn't seems to be executing the increment of the money.
Thanks in advance!
Board/index.js:
import React, { useState, useEffect } from "react";
import "./index.scss";
import { FaBomb, FaBox, FaFlag } from "react-icons/fa";
import img from "../../assets/ItemsToHide/barrels/barrel1.png";
import TreasureBoxes from "../TreasureBoxes";
import TopBar from '../TopBar';
import SandToHide from "../SandToHide";
const Board = ({ treasureBoxes, randomTop, randomLeft, sand}) => {
const [money, setMoney] = useState(0);
return (
<div className="board-container">
<TopBar money={money}></TopBar>
<div className="sand-to-hide-container">
{sand.map((sandd) => {
return (
<SandToHide
id={sandd.id}
img={sandd.img}
randomTop={randomTop}
randomLeft={randomLeft}
/>
)
})}
</div>
<div className="treasure-boxes-container">
{treasureBoxes.map((box) => {
return(
<TreasureBoxes
setMoney={setMoney}
money={money}
id ={box.id}
bomba = {box.bomba}
treasureBoxes={treasureBoxes}
randomTop={randomTop}
randomLeft={randomLeft}
/>
)
})}
</div>
</div>
);
};
export default Board;
Just make sure to have a callback in your TreasureBoxes component (it would be easier to answer to you if you provided the code for it):
<input onChange={(e)=> setMoney(e.target.value)}/>
This is the code of the component:
import React, {useState, useEffect} from 'react'
import NavBar from './Navbar'
import axios from 'axios'
import {Link, useHistory} from 'react-router-dom'
function mygroups() {
let profile_id = localStorage.getItem('profile_id')
const [group, setgroup]=useState([])
useEffect(()=>{
axios.get(`/getgroups?profile_id=${profile_id}`)
.then(res=>setgroup(res.data))
.then(res=>{
//localStorage.setItem("screen_name",res.data.screenname)
//localStorage.setItem("profile_id",res.data._id)
})
.catch(err=>console.log(err))
})
return (
<div>
<NavBar />
<h3 className='bg-primary p-2 text-center'>Groups</h3>
{
group.map((data,key)=>(
<div className='container'>
<h2>{data.name}</h2>
<span className='badge badge-dart p-2'>{data.name}</span>
<h6 className='text-white mt-4'>{data.no_members}</h6>
<hr style={{border:'1pz dotted white'}} />
</div>
))
}
</div>
)
}
export default mygroups
This was based off from another component that works perfectly fine. I just changed the variable names. Even when I comment out all of the code and just have the const [group, setgroup]=useState([]), I get this compile error right away. Any help is greatly appreciated. Thanks.
You need to tell React that mygroups is a functional component rather than a regular function, otherwise it won't permit you to use hooks in it. Change
function mygroups() {
to
function Mygroups() {
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