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

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);
}

Related

App is not rendering even when the state in the redux is changed

I am having two buttons in a component thats under App component. Even though it is dispatching actions and store is updated, App is not re-rendered. Ideally on button press, I add some dummy name that will be put inside array and then a different component is rendered based on number items inside this array.
Can someone tell what is going wrong, I am a beginner to react and redux
Sandbox: https://codesandbox.io/s/panel-item-with-redux-hxmihq?file=/src/PanelAdder.js
App.jsx
import React from "react";
import "./styles.css";
import { Panel } from "./Panel";
import PanelAdder from "./PanelAdder";
import { useSelector } from "react-redux";
export default function App() {
const panels = useSelector((state) => state.panelItems);
return (
<>
<PanelAdder />
<div className="cards-container">
{panels || [].map((name) => <Panel {...{ name }} />)}
</div>
</>
);
}
PanelAdder.jsx
import React from "react";
import { useDispatch } from "react-redux";
import { addPanel } from "./actions/counterActions";
export default function PanelAdder() {
const dispatch = useDispatch();
const handleClick = (name) => {
dispatch(addPanel(name));
};
return (
<>
<button onClick={() => handleClick("Panel 1")}> Add Panel 1</button>
<button onClick={() => handleClick("Panel 2")}> Add Panel 2</button>
</>
);
}
Panel.jsx
import React from "react";
import { FontAwesomeIcon } from "#fortawesome/react-fontawesome";
import {
faSquareMinus,
faWindowMaximize,
faRectangleXmark
} from "#fortawesome/free-solid-svg-icons";
export const Panel = ({ name }) => {
return (
<>
<div className="card">
<div className="card-actions">
<FontAwesomeIcon icon={faSquareMinus} />
<FontAwesomeIcon icon={faWindowMaximize} />
<FontAwesomeIcon icon={faRectangleXmark} />
</div>
<div className="card-body">{name}</div>
</div>
</>
);
};
You have 2 issues:
First in your combineReducers function you are adding the reducer called panels. Redux will add this to the state object. So when you are referencing it you need to refrence the panels object that is nested inside your state object. You need to get the following in your useSelector useSelector((state) => state.panel.panelItems)
Second you are doing the following in your app component {panels || [].map((name) => <Panel {...{ name }} />)}. So what you are doing here is displaying the panels array or mapping through an empty array but you never actually map through the panels array. But what you need to do is map through the panels array. So you can just map the panels array {panels.map((name) => <Panel {...{ name }} />)}
So your app component should look like the following:
import React from "react";
import "./styles.css";
import { Panel } from "./Panel";
import PanelAdder from "./PanelAdder";
import { useSelector } from "react-redux";
export default function App() {
const panels = useSelector((state) => state.panel.panelItems);
return (
<>
<PanelAdder />
<div className="cards-container">
{panels.map((name) => <Panel {...{ name }} />)}
</div>
</>
);
}

Modal Content isn't rendering while the Backdrop is - can't figure out the error

I am trying to implement a cart as a Modal on my project. The issue is that the Backdrop is rendering as it should but the Overlay isn't. It has been 30 minutes but I can't figure out the error, attaching the files below.
For now, the Modal should render all the time according to the code as I have yet to implement the conditional rendering but that isn't an issue, the issue is that the Overlay isn't showing up for some reason.
App.js file
import "./App.css";
import { useState } from "react";
import Middlebar from "./Components/Middlebar";
import FilterTab from "./Components/FilterTab";
import ProductPage from "./Components/ProductPage";
import Navbar from "./Components/Navbar";
import { Route, Switch } from "react-router-dom";
import Data from "./Components/data.json";
import ProductDetail from "./pages/ProductDetail";
import Cart from "./Components/Cart";
function App() {
const [searchedTerm, setSearchedTerm] = useState("");
const getSearchTerm = (term) => {
setSearchedTerm(term);
};
return (
<Switch>
<Route path="/" exact>
<Navbar onSearch={getSearchTerm} />,
<Cart/>,
<Middlebar />,
<div className="filter-product row">
{" "}
<FilterTab></FilterTab>{" "}
<ProductPage searchTerm={searchedTerm}></ProductPage>{" "}
</div>
</Route>
<Route path="/product/:id">
<ProductDetail></ProductDetail>
</Route>
</Switch>
);
}
export default App;
Modal.js file
import { Fragment } from "react";
import ReactDOM from "react-dom";
import "./Modal.css";
const Backdrop = (props) => {
return <div onClick = {props.onClick} className="backdrop"></div>;
};
const ModalOverlay = (props) => {
return (
<div className="modal">
<div className="content">{props.children}</div>
</div>
);
};
const portalElement = document.getElementById("overlays");
export default function Modal(props) {
return (
<Fragment>
{ReactDOM.createPortal(<Backdrop />, portalElement)}
{ReactDOM.createPortal(
<ModalOverlay>{props.children}</ModalOverlay>,
portalElement
)}
</Fragment>
);
}
Cart.js file
import React from "react";
import Modal from "../Modal";
import "./Cart.css";
export default function Cart() {
return (
<Modal>
<div className="total">
<span>Total</span>
<span>hi</span>
</div>
<div className="actions">
<button className="button--alt">
Close
</button>
<button className="button">Order</button>
</div>
</Modal>
);
}

How do I pass useState from one component to another?

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.

How do I disable a button in React for just one option if the button is a reusable React component?

Still learning React to the best of my ability so forgive me if this code isn't the most logical.
I have made a reusable CustomButton component in React to use across my app. I've then created 3 Card components on a Welcome page with each Card nesting this CustomButton inside of it, with each CustomButton using Link from react-router to navigate to different pages of the app. For the 3rd card, I would like to have this button disabled as this particular page will be 'coming soon'. I've been able to add a className to Link within props of the last Card to set the opacity of the text to look inactive, but want to be able to customise the entire button (not just the text within) to make it look greyed out etc.
Is there a simple way to do this?
This is my code so far:
Card:
import React, { useState } from 'react';
import { Card } from 'react-bootstrap';
import CustomButton from './CustomButton';
const WelcomeCard = (props) => {
return (
<>
<Card className='m-3 p-2 welcome-card rounded'>
<Card.Body className='welcome-card__body'>
<Card.Text>{props.text}</Card.Text>
<CustomButton link={props.link} />
</Card.Body>
</Card>
</>
);
};
export default WelcomeCard;
CustomButton:
import React from 'react';
const CustomButton = (props) => {
return <button className='custom-button'>{props.link}</button>;
};
export default CustomButton;
WelcomeScreen - The last component at the bottom is where I want to disable this CustomButton:
import React, { useState } from 'react';
import { Row, Col } from 'react-bootstrap';
import WelcomeCard from '../components/WelcomeCard';
import Loader from '../components/Loader';
import { Link } from 'react-router-dom';
const WelcomeScreen = () => {
const [loading, setLoading] = useState(false);
return (
<>
<div class='welcome-container'>
<div>
<h1 className='p-2 my-3 welcome-header'>Welcome</h1>
</div>
<div className='cards-container'>
<Row>
<Col>
<WelcomeCard
link={
<Link className='cards-link' to='/company'>
Company
</Link>
}
/>
</Col>
<Col>
<WelcomeCard
link={
<Link className='cards-link' to='/landscape'>
Landscape
</Link>
}
/>
</Col>
<Col>
<WelcomeCard
link={
<Link className='cards-link disabled-link' to='/insights'>
AI Insights
</Link>
}
/>
</Col>
</Row>
</div>
</div>
</>
);
};
export default WelcomeScreen;
Thanks in advance for any guidance!
Why you don't use props to solve this problem?
Edit your CustomButton like this:
import React from 'react';
const CustomButton = (props) => {
if(!props.active) return <button className='custom-button-disabled'></button>;
return <button className='custom-button'>{props.link}</button>;
};
export default CustomButton;
You can pass this prop into the CustomButton Component now like you are doing with the link prop.

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