How do I pass useState from one component to another? - javascript

I am trying to make a login modal that changes to the signup modal when the signup button is clicked within the Login.js. Currently, I have a header with a login button. When the login button is clicked, the current state is displayed (default value is ). I would like the signup button within Login.js to be able to update the state in order for that modal to .
Header.js:
import React, { useState } from 'react';
import Login from "../modals/Login";
import Signup from "../modals/Signup";
export default function Header() {
const [lmodal, setModal] = useState(<Login />);
return (
...
{lmodal}
...
)
}
Login.js
import React, { useState } from 'react';
import Signup from "../modals/Signup";
export default function Login() {
return (
...
**// Clicking the button should change the state from Header.js to <Signup />**
<button onClick={() => { setModal(<Signup />) }} className="btn btn-primary">Signup</button>
...
)
}
Thanks for the help in advance!

States and components are different in concept.
What you coould possible do to reach the wanted behavior is to use the state to toogle the component, for exemple:
import React, { useState } from 'react';
import Login from "../modals/Login";
import Signup from "../modals/Signup";
export default function Header() {
const [modal, setModal] = useState(false);
return (
...
{modal && <Login />}
<Signup modal={modal} setModal={setModal}/>
...
)}
import React, { useState } from 'react';
import Signup from "../modals/Signup";
export default function Login({modal, setModal}) {
return (
...
<button onClick={() => setModal(true)} className="btn btn-primary">Signup</button>
...
)
}

you can't setModal from within the Login component because setModal is in the Header component.

Related

how to use setTimeout on a react component

This question might be simple to most web developers but I am pretty new and cannot figure out the way to put a settimeout function on what I would like to show on a page. below is the example of the code I would like to add a timeout for.
import React from "react";
function Navbar() {
return (
<div className="navbar">
<h4>
Contact
</h4>
<h4>About Me</h4>
</div>
);
}
export default Navbar;
and here is my app.jsx which then will be exported to be used in index.js . What I want is to have lets say 5s delay before my Navbar function shows.
import React, { useEffect } from "react";
import Navbar from "./Navbar";
import Contact from "./Contact";
function App() {
return (
<div>
<Navbar />
<Contact />
</div>
);
}
export default App;
You can add setTimeout in your App Component. It should look like this:
import React, { useState, useEffect } from "react";
import Navbar from "./Navbar";
import Contact from "./Contact";
function App() {
const [showNavBar, setShowNavBar] = useState(false);
useEffect(() => {
const timer = setTimeout(() => {
setShowNavBar(true);
}, 5000);
return () => clearTimeout(timer);
}, [])
return (
<div>
{showNavBar ? <Navbar /> : null}
<Contact />
</div>
);
}
export default App;
your can add a state 'loading' and add useEffect hook and then use setTimeout there and change the loading state to false after 5seconds. in return section all you need to do is check if loading is false you show the otherwise it will show nothing.
import React, { useEffect, useState } from "react";
import Navbar from "./Navbar";
import Contact from "./Contact";
function App() {
const [loading, setLoading] = useState(true);
useEffect(() => {
setTimeout(() => {
setLoading(false);
}, 5000);
}, [])
return (
<div>
{!loading && <Navbar /> }
<Contact />
</div>
);
}
export default App;

How to target props of a component already nested inside another component

I am trying to render a different component in my App.js based on an OnClick placed in a button nested inside my Home component. Essentially I want the Home component to initially be rendered and then my "Restaurants" component to replace it when I click on the "Explore Restaurants" (which changes the state from true to false) button which is nested in my Home component. I am new to react so I'm sure there is an easy way to do this but I'm feeling a bit lost.
Here is the code
**App.js:**
import React, {useState} from "react";
import './App.css';
import Home from "./home"
import Footer from "./footer"
import Header from "./header"
import Resturants from "./resturants";
function App() {
var [count, setCount] = useState(false);
return (
<div>
<Header/>
{count ? <Home /> : <Resturants/> }
<Footer/>
</div>
);
}
export default App;
**Home.js**
import React, {useState} from "react";
import Button from "./button";
import {Stack} from "react-bootstrap";
import Promotions from './promotions'
//This component purely renders the home page when the user opens the app.
function Home (){
function changePage (){
setCount(count = true)
}
return (
<Stack>
<Promotions />
<Button className ="homeButtons" buttonText="Login" />
<Button className ="homeButtons" buttonText="Signup" />
<Button onClick ={changePage} className ="homeButtons" buttonText="Explore Resturants" />
</Stack>
)
}
export default Home
**Button.js**
import React from "react"
function Button (props){
return (<button onClick={props.onClick} style={props.style} className ={props.className} type = {props.type}> {props.buttonText} </button>
)
}
export default Button
You should pass the setCount method down to the Home component as a prop:
function App() {
var [count, setCount] = useState(false);
return (
<div>
<Header />
{count ? <Home setCount={setCount} /> : <Resturants />}
<Footer />
</div>
);
}
And then, retrieve it in the Home component:
function Home({ setCount }) {
function changePage() {
setCount((oldCount) => !oldCount);
}

How to use react-router-dom v6 navigate in class component

I installed react-router-dom v6 and I want to use a class based component, in previous version of react-router-dom v5 this.props.history() worked for redirect page after doing something but this code not working for v6 .
In react-router-dom v6 there is a hook useNavigate for functional component but I need to use it in class base component , Please help me how to use navigate in class component ?
In the react-router-dom v6, the support for history has been deprecated but instead of it, navigate has been introduced. If you want to redirect user to a specific page on success of a specific event, then follow the steps given below:
Create a file named as withRouter.js, and paste the code given below in this file:
import { useNavigate } from 'react-router-dom';
export const withRouter = (Component) => {
const Wrapper = (props) => {
const navigate = useNavigate();
return (
<Component
navigate={navigate}
{...props}
/>
);
};
return Wrapper;
};
Now, in whichever class based component you want to redirect the user to a specific path/component, import the above withRouter.js file there and use this.props.navigate('/your_path_here') function for the redirection.
For your help, a sample code showing the same has been given below:
import React from 'react';
import {withRouter} from '.your_Path_To_Withrouter_Here/withRouter';
class Your_Component_Name_Here extends React.Component{
constructor(){
super()
this.yourFunctionHere=this.yourFunctionHere.bind(this);
}
yourFunctionHere()
{
this.props.navigate('/your_path_here')
}
render()
{
return(
<div>
Your Component Code Here
</div>
)
}
}
export default withRouter(Your_Component_Name_Here);
Above Code works Perfect. And this is just a small extension.
If you want onclick function here is the code:
<div className = "row">
<button className= "btn btn-primary"
onClick={this.yourFunctionHere}>RedirectTo</button>
</div>
in class base component for redirect user follow this step :
first import some component like this
import { Navigate } from "react-router-dom"
now make a state for Return a boolean value like this:
state = {
redirect:false
}
now insert Naviagate component to bottom of your component tree
but use && for conditional rendring like this :
{
this.state.redirect && <Navigate to='/some_route' replace={true}/>
}
now when you want redirect user to some page just make true redirect state
on a line of code you want
now you can see you navigate to some page :)
Try this:
import {
useLocation,
useNavigate,
useParams
} from "react-router-dom";
export const withRouter = (Component) => {
function ComponentWithRouterProp(props) {
let location = useLocation();
let navigate = useNavigate();
let params = useParams();
return (
<Component
{...props}
router={{ location, navigate, params }}
/>
);
}
return ComponentWithRouterProp;
}
and just used this function, in my case:
import { withRouter } from '../utils/with-router';
import './menu-item.styles.scss';
const MenuItem = ({title, imageUrl, size, linkUrl,router}) =>(
<div
className={`${size} menu-item`} onClick={() => router.navigate(`${router.location.pathname}${linkUrl}`)}
>
<div className='background-image'
style={{
backgroundImage: `url(${imageUrl})`
}} />
<div className="content">
<h1 className="title">{title.toUpperCase()}</h1>
<span className="subtitle">SHOP NOW</span>
</div>
</div>
)
export default withRouter(MenuItem);
I found this solution here https://www.reactfix.com/2022/02/fixed-how-can-i-use-withrouter-in-react.html
Other solution is useNavigate, for example:
<button onClick={() => {navigate("/dashboard");}} >
Dashboard
</button>
In a react class component use <Navigate>. From the react router docs:
A <Navigate> element changes the current location when it is rendered. It's a component wrapper around useNavigate, and accepts all the same arguments as props.
Try creating a reusable functional Component like a simple button and you can use it in your class component.
import React from "react";
import { useNavigate } from "react-router-dom";
const NavigateButton = ( { buttonTitle, route,isReplaced}) => {
const navigate = useNavigate();
return (
<button
className = "btn btn-primary"
onClick = { () => {
navigate( route , {replace:isReplaced} )
}}
>
{buttonTitle}
</button>;
);
});
export default NavigateButton;
After this, you can use NavigateButton in any of your class Components. And it will work.
<NavigateButton title = {"Route To"} route = {"/your_route/"} isReplaced = {false}/>
Found this explanation from the GitHub react-router issue thread, this explained how to use react-router 6 with class components
https://github.com/remix-run/react-router/issues/8146
I got this code from the above issue explanation
import React,{ Component} from "react";
import { useNavigate } from "react-router-dom";
export const withNavigation = (Component : Component) => {
return props => <Component {...props} navigate={useNavigate()} />;
}
//classComponent
class LoginPage extends React.Component{
submitHandler =(e) =>{
//successful login
this.props.navigate('/dashboard');
}
}
export default withNavigation(LoginPage);
If you need to use params for data fetching, writing a logic in your ClassComponent and render component depending on them, then create wrapper for your ClassComponentContainer
import { useLocation, useParams } from 'react-router-dom';
import ClassComponentContainer from './ClassComponentContainer';
export default function ClassComponentWrap(props) {
const location = useLocation();
const params = useParams();
return <ClassComponentContainer location={location} params={params} />
}
after it just use params in ClassComponent which is in props
import React from 'react';
import { connect } from 'react-redux';
import axios from 'axios';
import PresentationComponent from './PresentationComponent';
class ClassComponent extends React.Component {
componentDidMount() {
let postID = this.props.params.postID;
axios.get(`https://jsonplaceholder.typicode.com/posts/${postID}`)
.then((response) => {console.log(response)})
}
render() {
return <PresentationComponent {...this.props} />
}
}
const mapStateToProps = (state) => {...}
const mapDispatchToProps = (dispatch) => {...}
const ClassComponentContainer = connect(mapStateToProps, mapDispatchToProps)(ClassComponent);
export default ClassComponentContainer;
and use ClassComponentWrap component in Route element attribute
import { BrowserRouter, Route, Routes } from "react-router-dom";
import ClassComponentWrap from './components/ClassComponentWrap';
export default function App(props) {
return (
<BrowserRouter>
<Routes>
<Route path="/posts/:postID?" element={<ClassComponentWrap />} />
</Routes>
</BrowserRouter>
);
}
Here is my solution:
import React, { Component } from "react";
import { useNavigate } from "react-router-dom";
class OrdersView extends Component {
Test(props){
const navigate = useNavigate();
return(<div onClick={()=>{navigate('/')}}>test{props.test}</div>);
}
render() {
return (<div className="">
<this.Test test={'click me'}></this.Test>
</div>);
}
}

How to hide a button unless a variable has a value

I am trying to create a logoff button in react, and although it works (logs the user out) I want to make the button hidden unless my localstorage has a value for 'token'. At this point when it is not null, I would like my logoff button to then appear on screen for a user to logoff.
The section where I call this button is below, which currently only has an onclick event if my localstorage has a value assigned to 'token'
import React from "react";
import { render } from "react-dom";
import Login from "./Login";
import Register from "./Register";
import Logout from "./logout";
import Button from "react-bootstrap/Button";
render(
<>
<Login />
<div>
<h1>OR</h1>
</div>
<Register />
</div>
<Button onClick={event => {if(localStorage.getItem('token') !== null)
Logout()}} }>Logout</Button>
</>,
document.getElementById("root")
);
Currently this works as intended, but is not hidden. I have thought about creating a function that exports only a button if the paramater is fulfilled as posted below;
import Logout from "./logout";
import Button from "react-bootstrap/Button";
import React from "react";
function logoffBut(){
if (localStorage.getItem("token") !== null) {
return <Button onClick={event => Logout()}>Logout</Button>;
}
}
export default logoffBut;
then calling
<logoffBut />
in my render above, in place of the current logout button that is there.
However when I log in and store the 'token' in local storage,
it does not generate the logoffBut at this point, despite the token being correctly stored in my local storage?
I would just like some help to see how I should be writing this function to be checking if my 'token' in local storage is not null, and if it is not null, to then generate the logoff button.
Thank you.
You can a ternary operator to check and render only if required
localStorage.getItem('token') !== null ? <Button onClick={event => {if(localStorage.getItem('token') !== null) Logout()}} }>Logout</Button> : null;
Suggestion
I suggest you also to split your content to another component something like
import React from "react";
import { render } from "react-dom";
import Login from "./Login";
import Register from "./Register";
import Logout from "./logout";
import Button from "react-bootstrap/Button";
import loginPage from "./LoginPage";
render(<loginPage></loginPage>,document.getElementById("root")
);
You can use && operator to render the button when localStorage is not null
{localStorage.getItem('token') !== null && <Button> ... </Button>}
Use conditional rendering in JSX
import React from "react";
import { render } from "react-dom";
import Login from "./Login";
import Register from "./Register";
import Logout from "./logout";
import Button from "react-bootstrap/Button";
render(
<>
<Login />
<div>
<h1>OR</h1>
</div>
<Register />
</div>
{
localStorage.getItem('token') !== null ? <Button onClick={event => Logout()>Logout</Button>: null
}
</>,
document.getElementById("root")
);
I love using the display-if prop.
<div display-if={someCondition}>MY TEXT</div>
You can use it after installing the babel plugin
https://www.npmjs.com/package/babel-plugin-jsx-display-if

How would I my component work inside another component without repeating code?

How would I make my component work inside another component without repeating code?
In other words, inside NextPage.js file, the <LogoutButton/> component won't carry out its function? I want the <LogoutButton/> to carry out the exact same function as it does inside the <Home/> component.
Is there a way to do this without making NextPage.js a class based component and repeating the same logic inside NextPage.js component?
Here's the Home.js file:
import React, {Component} from 'react';
import fire from '../../config/Fire';
import classes from './Home.css';
import Aux from '../../hoc/Aux';
import NextPage from '../../components/nextpage/NextPage';
import LogoutButton from '../../UI/buttons/LogoutButton';
class Home extends Component {
state = {
flag: false
}
logout() {
fire.auth().signOut();
}
goToNextPage() {
this.setState({flag: true});
}
render() {
const flag = this.state.flag;
if(flag) {
return <NextPage/>;
}
return (
<Aux>
<button
type="button"
className="btn btn-outline-primary btn-lg btn-block"
onClick={this.goToNextPage.bind(this)}>some button
</button>
<LogoutButton clicked={this.logout.bind(this)}/>
<NextPage/>
</Aux>
);
}
}
export default Home;
Here's the NextPage.js file:
import React from 'react';
import Aux from '../../hoc/Aux';
import LogoutButton from '../../UI/buttons/LogoutButton';
const nextPage = () => {
return(
<Aux>
<LogoutButton/>
</Aux>
);
}
export default nextPage;
Here's the LogoutButton.js file:
import React from 'react';
import classes from '../../UI/buttons/LogoutButton.css';
import Aux from '../../hoc/Aux';
const logoutButton = (props) => (
<Aux>
<button
className={classes.LogoutButton}
onClick={props.clicked}>Logout
</button>
</Aux>
);
export default logoutButton;
You can move your logout logic into the logout button component. Function handler is better when your logout logic becomes complex.
import React from 'react';
import classes from '../../UI/buttons/LogoutButton.css';
import Aux from '../../hoc/Aux';
import fire from '../../config/Fire';
const handleLogout = () => {
fire.auth().signOut();
}
const logoutButton = (props) => (
<Aux>
<button
className={classes.LogoutButton}
onClick={handleLogout}
>
Logout
</button>
</Aux>
);
export default logoutButton;
You don't need to duplicate all logic since your logout logic does not depend on Home component.
// NextPage.js
import React from 'react';
import fire from '../../config/Fire';
import Aux from '../../hoc/Aux';
import LogoutButton from '../../UI/buttons/LogoutButton';
const nextPage = () => {
return(
<Aux>
<LogoutButton onClick={fire.auth().signOut} />
</Aux>
);
}
export default nextPage;
Or, if fire.auth() is potentially an expensive function you can write it like this:
onClick={() => fire.auth().signOut()}
why don't you move the fire.auth().signOut(); line inside the logout button ?
import React from 'react';
import classes from '../../UI/buttons/LogoutButton.css';
import Aux from '../../hoc/Aux';
import fire from '../../config/Fire';
const logoutButton = (props) => (
<Aux>
<button
className={classes.LogoutButton}
onClick={() => fire.auth().signOut()}>Logout
</button>
</Aux>
);
export default logoutButton;
Unless I am missing something, the only usage of fire in Home component is that one. Why don't you put it in the logout component ?
Furthermore, you don't need to pass that as prop now, and it will behave the same everywhere you place it
You can pass functions that are in Home into NextPage as props e.g.
<NextPage goToNextPage={this.goToNextPage} />
then inside NextPage you can use that by calling props.NextPage()
Also if you write your goToNextPage function as an arrow function then you dont need to bind it
goToNextPage = () => this.setState({flag: true});

Categories