How to replace one React Component with another OnClick? - javascript

I have a "sign up" button. When it is clicked, I would like for it to render a new component, called "SignUp". I would like for the new component to replace the "sign up" button.
Currently, I am using setState so that when the button is clicked, a new component is rendered. However, the button is not being replaced, the "SignUp" component is just rendered beside the button. What may be a good approach for me to replace the button with the new component being rendered?
I have provided my code below:
export default class SignUpSignIn extends Component {
constructor() {
super();
this.state = {
clicked: false
};
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState({
clicked: true
});
}
render () {
return (
<div id="SignUpSignInDiv">
<Col md="12" sm="12" xs="12" className="text-center">
<div onClick={this.handleClick}>
{this.state.clicked ? <SignUp /> : null}
<Button id="SignUpButton" color="primary"> Sign Up </Button>
</div>
</Col>
</div>
)
}
}

Well, you're not rendering both components conditionally, only the SignUp. Instead of having null in your ternary, render the sign in button when state.clicked === false:
render () {
return (
<div id="SignUpSignInDiv">
<Col md="12" sm="12" xs="12" className="text-center">
{this.state.clicked ? (
<SignUp />
) : (
<Button id="SignUpButton" color="primary" onClick={this.handleClick}> Sign Up </Button>
)}
</Col>
</div>
)
}

one way to do it is like this , i didnt test it yet but it should work
render () {
let show = <div></div>
if(this.state.clicked){
show = <SignUp />
}
return (
<div id="SignUpSignInDiv">
<Col md="12" sm="12" xs="12" className="text-center">
{show}
<Button id="SignUpButton" color="primary" onClick={this.handleClick}> Sign Up </Button>
</Col>
</div>
)
}

Related

how to open modal2 from a button of modal1 in react

I have two modals one is Login modal and another is Signup modal now I want to open signup modal by clicking on a button which is present in login modal, I tried many different ways but not able to achieve it, also I tried to make a signupModalSwitch with useReducer and by making different function calls but it was saying against hooks rule, I am very new to react not able to figure out how to do it. Thanks in Advance :)
modal1 ->
function LoginModal() {
const [open, setOpen] = React.useState(false);
const handleOpen = () => {
setOpen(true);
};
const handleClose = () => {
setOpen(false);
};
return (
<div>
<Button
onClick={handleOpen}
variant="outlined"
className={classNames(
classes.textNeonGreen,
classes.outlinedNeonGreen,
classes.navButton
)}
classes={{ disabled: classes.disabled }}
>
<Typography noWrap>Login</Typography>
</Button>
<Modal
className={classes.modal}
open={open}
onClose={handleClose}
closeAfterTransition
BackdropComponent={Backdrop}
BackdropProps={{
timeout: 500,
}}
>
<Fade in={open}>
<LoginCard LoginClose={handleClose} />
</Fade>
</Modal>
</div>
);
}
function LoginCard({ LoginClose }) {
return (
<Card className={classes.modalCard}>
<span>
<button
onClick={LoginClose}
type="button"
className="close px-2 pt-2"
aria-label="Close"
>
<span aria-hidden="true">×</span>
</button>
</span>
<CardContent className={classes.modalCardContent}>
<Typography variant="h4" className={classes.modalHeading}>
<b>Login</b>
</Typography>
<Account>
<Login />
</Account>
<div>
<Grid
container
direction="column"
justify="center"
alignItems="center"
>
<p className="mb-2 mt-4 text-center">
Don't have Account?
</p>
//###### BY CLICKING THIS BUTTON I WANT TO OPEN MY SIGNUP MODAL #######//
<button
className="btn btn-outline-success btn-block btn-md"
onClick={() => {
LoginClose();
signupModalSwitch(null,{type:'open'})
}
}
>
Signup
</button>
</Grid>
</div>
</CardContent>
</Card>
);
}
MODAL2 ->
function signupModalSwitch(state, action){
switch(action.type){
case 'open':
return { open: true }
case 'close':
return { open: false }
default:
console.log(action);
}
}
function SignupModal() {
const classes = useStyles();
const [state, dispatch] = useReducer(signupModalSwitch, { open: false })
function handleOpen() {
dispatch({type: "open"});
}
function handleClose() {
dispatch({type: "close"});
};
return (
<div>
<Button
onClick={handleOpen}
variant="outlined"
className={classNames(
classes.textNeonGreen,
classes.outlinedNeonGreen,
classes.navButton
)}
classes={{ disabled: classes.disabled }}
>
<Typography noWrap>Signup</Typography>
</Button>
<Modal
className={classes.modal}
open={state.open}
onClose={handleClose}
closeAfterTransition
BackdropComponent={Backdrop}
BackdropProps={{
timeout: 500,
}}
>
<Fade in={state.open}>
<SignupCard signupClose={handleClose} />
</Fade>
</Modal>
</div>
);
}
function SignupCard({ signupClose }) {
return (
<Card className={classes.modalCard}>
<span>
<button
onClick={signupClose}
type="button"
className="close px-2 pt-2"
aria-label="Close"
>
<span aria-hidden="true">×</span>
</button>
</span>
<CardContent className={classes.modalCardContent}>
<Typography variant="h4" className={classes.modalHeading}>
<b>Signup</b>
</Typography>
<Signup />
</CardContent>
</Card>
);
}
A better way to do this would be to create a container and move all the logic to the container. Your login and sign up modals should be dumb components, i.e, do not maintain the state in these components.
In your container, keep two states, openLoginModal and openSignupModal.
const [openLoginModal, setOpenLoginModal] = useState(false)
const [openSignupModal, setOpenSignupModal] = useState(false)
You can pass these as props to your login and signup components. When you click the button in the login modal, you will need one more function that closes login modal and opens sign up modal. You can pass this as prop as well.
const onSignupButtonClick = () => {
setOpenLoginModal(false)
setOpenSignupModal(true)
}
You can conditionally render login and signup modal based on the state values.

How to tigger onClick function of another component element

I created one class base component and one functional component. There are three buttons inside the functional component and I called that component to my class based component.
The functional component:
function PanelButton(props){
return (
<div>
<Button.Ripple
color="success"
type="submit"
style={{margin:"5px", width:"110px"}}
>
Submit
</Button.Ripple>
<Button.Ripple
color="primary"
id="clearButton"
type="button"
style={{margin:"5px", width:"110px"}}
>
Clear
</Button.Ripple>
<Button.Ripple color="danger" type="button" style={{margin:"5px", width:"110px"}}>
Close
</Button.Ripple>
</div>
)
}
export default PanelButton;
The class base component, in which I imported the functional component into:
import PanelButton from '../../components/customzied/PanelButton';
class TicketNew extends React.Component{
state = {
alertOption:[],
}
clickClear = () => {
console.log("ok");
}
render() {
const rqst = this.state.rquirdSate;
return (
<Card>
<Formik>
{ ({ errors, touched}) => (
<div>
<Form onSubmit={handleSubmit}>
<CardHeader>
<PanelButton />
</CardHeader>
<CardBody>
<Row />
</CardBody>
</Form>
</div>
)}
</Formik>
</Card>
)
}
}
export default TicketNew;
When I click the button(id = "clearButton") from functional component, I need to run the Click clear function in Class component.
You can pass onClick callback handlers as props to PanelButton to attach to each button's onClick prop. Pass clickClear as callback for clear button.
PanelButton
function PanelButton(props) {
return (
<div>
...
<Button.Ripple
color="primary"
id="clearButton"
type="button"
style={{ margin: "5px", width: "110px" }}
onClick={props.onClear} // <-- attach callback to button's onClick handler
>
Clear
</Button.Ripple>
...
</div>
);
}
TicketNew
class TicketNew extends React.Component {
state = {
alertOption: []
};
clickClear = () => {
console.log("ok");
};
render() {
const rqst = this.state.rquirdSate;
return (
<Card>
<Formik>
{({ errors, touched }) => (
<div>
<Form onSubmit={handleSubmit}>
<CardHeader>
<PanelButton onClear={this.clickClear}/> // <-- pass this.clickClear to onClear prop
</CardHeader>
<CardBody>
<Row></Row>
</CardBody>
</Form>
</div>
)}
</Formik>
</Card>
);
}
}
You can pass the clickClear function as props to the PanelButton component. The PanelButton code will look like the following,
function PanelButton(props){
return(
<div>
<Button.Ripple color="success" type="submit" style={{margin:"5px", width:"110px"}}>
Submit
</Button.Ripple>
<Button.Ripple color="primary" id="clearButton" onClick={props.onClickCallback} type="button" style={{margin:"5px", width:"110px"}}>
Clear
</Button.Ripple>
<Button.Ripple color="danger" type="button" style={{margin:"5px", width:"110px"}}>
Close
</Button.Ripple>
</div>
)
}
And the TicketNew code will look like this,
...
<CardHeader>
<PanelButton onClickCallback={this.clickClear.bind(this)} />
</CardHeader>
...

Toggle CSS style in a function React component

Every post or tutorial on how to toggle css in React assumes that I'm using a class component. However, I'm using a function component and don't have access to this and state. Can somebody tell me how to toggle a CSS style for a JSX element in a React function component?
import React from 'react';
import { Row, Container, Col } from 'react-bootstrap';
const FilterBar = ( {eventFilters, setEventFilters} ) => {
const someFunction = () => {
// code in here
}
return(
<div className="row-fluid" >
<Container fluid >
<Row className="justify-content-md-center mb-2 mt-2">
<Col onClick={someFunction}> <button value="ALL"> All </button> </Col>
<Col onClick={someFunction}> <button value="WORKSHOP"> Workshop </button> </Col>
<Col onClick={someFunction}> <button value="MINIEVENT"> Minievent </button> </Col>
</Row>
<Row className="justify-content-md-center mb-2">
<Col onClick={someFunction}> <button value="SPEAKER"> Speaker </button></Col>
<Col onClick={someFunction}> <button value="MEAL"> Meal </button> </Col>
<Col onClick={someFunction}> <button value="OTHER"> Other </button> </Col>
</Row>
</Container>
</div>
);
}
export default FilterBar;
Toggling some style via click event object. You can use the event target style property to change the current textDecoration property to "line-through" or nothing ("").
const toggleStrikethrough = (e) => {
e.target.style.textDecoration =
e.target.style.textDecoration === "line-through" ? "" : "line-through";
};
function App() {
const toggleStrikethrough = (e) => {
e.target.style.textDecoration =
e.target.style.textDecoration === "line-through" ? "" : "line-through";
};
return (
<div className="App">
<div onClick={toggleStrikethrough}>ALL</div>
<div onClick={toggleStrikethrough}>WORKSHOP</div>
<div onClick={toggleStrikethrough}>MINIEVENT</div>
<div onClick={toggleStrikethrough}>SPEAKER</div>
<div onClick={toggleStrikethrough}>MEAL</div>
<div onClick={toggleStrikethrough}>OTHER</div>
</div>
);
}
Note: This is generally frowned upon though and considered an anti-pattern as you are directly manipulating the DOM. The better and more react way is to maintain a toggled "state" in local component state for each element you want to toggle style (or anything really) of.

Enable button based on map value React

I have a component that renders a list of books into bootstrap cards with a checkout button. I have a state for the checkout button called disabled.
I want to enable the button only if the books.quantity>0. How can I successfully change the state of this button?
constructor(props) {
super(props)
this.state = {
books: [],
message: null,
disabled: true
}
}
render() {
return (
<Container fluid>
<Row>
{
this.state.books.map(
books =>
<Col key={books.id} sm="2">
<Card style={{ width: '18rem' }}>
<Card.Img variant="top" src="http://res.freestockphotos.biz/pictures/14/14301-illustration-of-a-book-pv.png" />
<Card.Body>
<Card.Title>{books.title}</Card.Title>
<Card.Subtitle> {books.author.firstName + " " + books.author.lastName} </Card.Subtitle>
<Card.Subtitle > {books.quantity} </Card.Subtitle>
<Button disabled={this.state.disabled} variant="primary" >Checkout</Button>
</Card.Body>
</Card>
</Col>
)
}
</Row>
</Container>
);
}
You can add to the disabled attribute the following:
<Button disabled={books.quantity > 0} variant="primary">Checkout</Button>
This will check the value of books.quantity > 0 and enable the button if the statement is true.

Passing a javascript variable to a css variable via an HTML style attribute in react component

It is a bit hard to explain what it is exactly I am trying to do, but it should be pretty obvious by looking at the code.
Here is the full code for the react component, take note that the endpoint that populates the prop is missing as it hasnt been developed yet.
import React, { useState } from 'react';
import { Modal, ModalHeader, ModalBody, Button, Row, Col, Container } from 'reactstrap'
import '../../scss/hitchpin/star-rating.scss'
const ReviewModal = (props: Props) => {
const {
offering,
ratings,
comments,
response,
} = props
const [modal, setModal] = useState(false);
const [sellerReviews, setSellerReviews] = useState(false);
const toggle = () => {
setModal(!modal);
if (document.getElementById('seller').onclick) {
setSellerReviews(!sellerReviews);
}
}
return (
<div>
<Button id="seller" className="btn-sm ml-2 btn btn-secondary" onClick={toggle}> Seller Review Details </Button>
<Button className="btn-sm ml-2 btn btn-secondary" onClick={toggle}> Buyer Review Details </Button>
<Modal isOpen={modal} toggle={toggle}>
<ModalHeader toggle={toggle}>Review Details</ModalHeader>
<ModalBody>
<div>
<Container>
<Row>
<Col>As a Seller</Col>
</Row>
</Container>
</div>
<div className="p-3">
<h3>{offering.title}</h3>
<p>Category: {offering.category}</p>
<Container>
<Row>
<Col xs="6">Overall</Col>
<Col xs="6" class="Stars" style={'--ratings:' ratings.overall}></Col>
</Row>
<Row>
<Col xs="6">Response Time</Col>
<Col xs="6" class="Stars" style={--ratings: ratings.response}></Col>
</Row>
<Row>
<Col xs="6">Friendliness</Col>
<Col xs="6" class="Stars" style={--ratings: ratings.friendliness}></Col>
</Row>
<Row>
<Col xs="6">Punctuality</Col>
<Col xs="6" class="Stars" style={--ratings: ratings.punctuality}></Col>
</Row>
{sellerReviews && (
<Row>
<Col xs="6">Quality of Product/Service</Col>
<Col xs="6" class="Stars" style={--ratings: ratings.quality}></Col>
</Row>
)}
</Container>
<div>
<p>{!sellerReviews ? "Buyer's Comments:" : "Seller's Comments"}</p>
<textarea readOnly>
{comments.message && (
{comments.message}
)}
</textarea>
</div>
<div>
<p>{sellerReviews ? "Buyer's Response:" : "Seller's Response"}</p>
<textarea readOnly>
response.message && (
{response.message}
)}
</textarea>
</div>
</div>
</ModalBody>
</Modal>
</div>
);
}
export default ReviewModal
The issue I am having is, in the <Col> tags with the style attribute, I need to pass the prop ratings.category to the --ratings css variable. I know that if the number was static I could easily pass --ratings: 2.5, which is how i tested the code. However, in implementation, the floating point number will be variable and changing. Hence the issue.
First of all, I believe that
<Col xs="6" class="Stars" style={'--ratings:' ratings.overall}></Col>
should be
<Col xs="6" class="Stars" style={{'--ratings': ratings.overall}}></Col> (notice extra braces)
Also, if values are numeric, React might add 'px'. You might want to convert to string:
<Col xs="6" class="Stars" style={{'--ratings': String(ratings.overall)}}></Col>
UPD
Here is an example with latest React version (old versions do not support css variables via style prop): https://codesandbox.io/s/shy-star-mxu74

Categories