Component is rendered before clicking on button in Reactjs - javascript

I am new to Reactjs . I am making a todo app using it . So in developing phase I want the Delete Button to console.log() the "hello" onClick. But whenever I submit a new todo task , even without click the delete button it console.log() the "hello" and if then I click Delete Button nothing happens on console.
I can't understand where's the problem . I surfed the internet but nothing worked.
May anyone tell where's the problem ?
Here's my code :
import './styles/App.css';
import { useState } from 'react';
import { Form, Button, ListGroup } from 'react-bootstrap';
import DropDown from './components/DropDowns';
import DeleteButton from './components/DeleteButton';
function App() {
const [todoList, setTodo] = useState([]);
const [Ttitle, setTitle] = useState('');
const [desc, setDesc] = useState('No Description');
return (
<div className="App d-flex flex-column">
<h1 className="mt-3">Your ToDo App</h1>
<div className="container-fluid mx-0 px-0">
<div className="Todo__Res mx-5">
<h2>Your ToDo List</h2>
<div className="List">
<ul className="Todo__List">
{todoList ? todoList.map((item, index) => <li key={index}>
<ListGroup>
<ListGroup.Item>{item.title}<DropDown desc={item.desc} /><DeleteButton index={index}/></ListGroup.Item>
</ListGroup>
</li>) : 0}
</ul>
</div>
</div>
<div className="Todo__Add mx-5">
<h2>Add Your ToDo</h2>
<Form>
<Form.Group controlId="exampleForm.ControlInput1">
<Form.Label>Title</Form.Label>
<Form.Control type="text" placeholder="Take Jack to School..." onChange={e => setTitle(e.target.value)} />
</Form.Group>
<Form.Group controlId="exampleForm.ControlTextarea1">
<Form.Label>Description</Form.Label>
<Form.Control as="textarea" rows={3} placeholder="Buy him a cake..." onChange={e => setDesc(e.target.value)} onDefault={desc} />
</Form.Group>
<Button variant="primary" type="submit" onClick={(e) => {
e.preventDefault();
const kk = {
title: Ttitle,
desc: desc
}
setTodo([...todoList, kk]);
}}>
Submit
</Button>
</Form>
</div>
</div>
</div>
);
}
export default App;
//Delete Button Component :
import {Button}from 'react-bootstrap'
export default function DeleteButton({index}){
return(
<>
<Button variant="outline-danger" onClick={console.log("hello")}>Delete</Button>
</>
);
}
Thanking You ,
Yours Truly
Rishabh Raghwendra

You are calling the function immediately on render. you should just pass a function to be executed on click
Here you go, this should fix your code issue,
<Button variant="outline-danger" onClick={() => console.log("hello")}>Delete</Button>

Related

React won't update child component props on setState (functional component with hooks)

I have this react parent component with 2 child components that interact with each other, one is a list of previous transactions and the other is a form to edit those aforementioned transactions.
I need to be able to click on a transaction mount the component and show the data to be edited, that all works fine,the problem is that ... say that i want to edit another transaction without unmounting the component, i can't do it because... once the component is mounted i can't re-update the data within it without unmounting and remounting the component with the new data
PARENT ELEMENT
import React, { useState, useEffect } from 'react';
import postServices from '../../api/postServices';
import LastTransactions from './partials/LastTransactions';
import NewTransaction from './partials/NewTransaction';
import TransactionPreviewEdit from './partials/TransactionPreviewEdit';
function Transactions(lastTransactions){
const [TPE_state, setTPE_state] = useState(false);
const [TPE_data, setTPE_data] = useState();
function editTransaction(transactionProps) {
setTPE_state(true)
setTPE_data(transactionProps)
}
function sendForm(){
}
function cancelTransaction(){
setTPE_state(false)
}
return(
<React.Fragment>
<div className="lastTransactionList col-md-6">
<LastTransactions transactions={lastTransactions} edit={editTransaction} />
</div>
<div className="lastTransactionPreviewEdit col-md-6">
{TPE_state ? <TransactionPreviewEdit transaction={TPE_data} cancelMethod={cancelTransaction} sendMethod={sendForm} /> : <NewTransaction edit={editTransaction}/>}
</div>
</React.Fragment>
)
}
export default Transactions;
TRANSACTION LIST COMPONENT (CHILD)
import React from 'react';
import SmallListCard from './SmallListCard';
function TransactionList(transProps){
let allTransactions = Object.values(transProps.transactions)
let editTransaction = transProps.edit
return (
<React.Fragment>
<h3 className="fw-bold text-primary">Ultimas Transacciones</h3>
<div>
{allTransactions.map((transaction,index)=>{
return <SmallListCard {...{transaction, editTransaction}} key= {index}/>
})}
</div>
</React.Fragment>
)
}
export default TransactionList;
TRANSACTION EDIT COMPONENT (CHILD)
import React from 'react';
import Form from 'react-bootstrap/Form'
import TextAreaInput from './TextAreaInput';
import TextInput from './TextInput';
import SelectInput from './SelectInput';
import { Button } from 'react-bootstrap';
function TransactionPreviewEdit({transaction, cancelMethod, sendMethod}){
let options = [
{id:1, name:"Servicios"},
{id:2, name:"Vivienda"},
{id:3, name:"Viáticos"},
{id:4, name:"Salud"},
{id:5, name:"Limpieza"},
{id:6, name:"Comida"},
{id:7, name:"Indumentaria"},
{id:8, name:"Cuidado Personal"},
{id:9, name:"Ocio"},
{id:10, name:"Otro"}
]
return (
<React.Fragment>
<h3 className="fw-bold text-white">.</h3>
<div className="bg-light rounded shadow my-3 p-2">
<form>
<Form.Group className="mb-1" controlId="cuenta">
<small>Cuenta</small>
<Form.Select aria-label="cuentas" size="sm" defaultValue={transaction.accountId.id}>
{options.map((props,index)=>{
return <option key={index} value={`${props.id}`} >{props.name}</option>
})}
</Form.Select>
</Form.Group>
<Form.Group className="mb-1" controlId="nombre">
<small>Nombre</small>
<Form.Control type="text" defaultValue={transaction.name} size="sm" />
</Form.Group>
<Form.Group className="mb-1" controlId="categoria">
<small>Categoria</small>
<Form.Select aria-label="categorias" size="sm" defaultValue={transaction.categoryId.id}>
{options.map((props,index)=>{
return <option key={index} value={`${props.id}`} >{props.name}</option>
})}
</Form.Select>
</Form.Group>
<Form.Group className="mb-1" controlId="medio">
<small>Medio</small>
<Form.Select aria-label="medios" size="sm" defaultValue={transaction.methodId.id}>
{options.map((props,index)=>{
return <option key={index} value={`${props.id}`} >{props.name}</option>
})}
</Form.Select>
</Form.Group>
<Form.Group className="mb-1" controlId="descripcion">
<small>Descripcion</small>
<Form.Control as="textarea" rows={2} defaultValue={transaction.description} size="sm" />
</Form.Group>
<Form.Group className="mb-1" controlId="Monto">
<small>Monto</small>
<Form.Control type="text" defaultValue={transaction.amount} size="sm"/>
</Form.Group>
<div className="d-flex justify-content-end mt-2">
<Button variant="danger" className="rounded p-1 px-3 me-2" onClick={cancelMethod}>Cancelar</Button>
<Button variant="primary" className="rounded p-1 px-3" onClick={sendMethod}>{transaction.id ? "Editar Transaccion" : "Añadir Transaccion"}</Button>
</div>
</form>
</div>
</React.Fragment>
)
}
TransactionPreviewEdit.defaultProps = {transaction:{
accountId:{},
datetime: "",
name: "",
categoryId: {},
methodId: {},
description: "",
amount:"",
}}

Custom PopUp modal component not showing when clicked in React

I am trying to show a custom PopUp component on the screen when a user clicks on the Info icon but nothing is rendering in the UI when clicked.
I'm not exactly certain where I'm going wrong if anyone could provide some guidance?
Here is my Card component with PopUp inside the return:
import React, { useState } from 'react';
import { Card } from 'react-bootstrap';
import InfoIcon from '#material-ui/icons/Info';
import PopUp from './PopUp';
const WelcomeCard = (props) => {
const [show, setShow] = useState(false);
const togglePop = () => {
setShow(true);
};
return (
<Card className='m-3 p-2 welcome-card rounded'>
<Card.Body>
<Card.Text className='mt-4'>{props.text}</Card.Text>
<Card.Title>{props.title}</Card.Title>
<button>{props.button}</button>
{show && <PopUp toggle={togglePop} />}
<InfoIcon className='info-icon' onClick={togglePop} />
</Card.Body>
</Card>
);
};
export default WelcomeCard;
And my actual PopUp component itself:
import React from 'react';
const PopUp = (props) => {
const handleClick = () => {
props.toggle();
};
return (
<div className='modal'>
<div className='modal_content'>
<span className='close' onClick={handleClick}>
×
</span>
<form>
<h3>Register!</h3>
<label>
Name:
<input type='text' name='name' />
</label>
<br />
<input type='submit' />
</form>
</div>
</div>
);
};
export default PopUp;
Would really appreciate some help on this one to understand it better, thanks in advance!

Trying to switch between modal components using React

So I have a start page that gives options to open a login modal or sign up modal. However, once you are in the login modal I give an option so you can switch to sign up modal. However, I can't seem to get this to work. The one time I got it to work, the modal showed up in the wrong section of the screen since it was being opened in relation to the login modal and not the start page.
I am new to React so any insight would be appreciated. Should I use redux, since I can't pass props from child to parent. So that way when I return to start page I can rerender with info saying that I had clicked sign-up link on the login modal.
function LoginContent(props) {
const [ open, setOpen ] = useState(false)
const { show, closeModal } = props;
function handleSubmit(e){
e.preventDefault();
}
function handleSignUpButton(){
closeModal();
console.log(open)
setOpen(!false)
console.log(open)
}
//added so that the component doesn't get affected by parent css
//and is being rendered from the "modal-root" DOM node from the index.html file
return ReactDOM.createPortal(
<>
<div className={show ? "overlay" : "hide"} onClick={closeModal} />
<div className={show ? "modal" : "hide"}>
<button onClick={closeModal} id="close">X</button>
<div className="login_form">
<h1> Log in to Continue </h1>
<form onSubmit={handleSubmit}>
<input className="username" type='text' name='username' placeholder='Email Address' />
<input className="password" type='password' name='password' placeholder='password' />
<button className="login_button"> Sign In</button>
</form>
</div>
<div className="login_demo">
<h3 className="login_demo_pointer" type="submit">Demo Login</h3>
</div>
<hr />
<div className="login_switch">Don't have an account.
<button className="signup_link" onClick={handleSignUpButton}>Sign Up</button>
{open && <SignUpContent open={open} closeModal={closeModal} show={show} />} </div>
</div>
</>, document.getElementById("modal-root")
);
}
function Start() {
const history = useHistory();
const [showLogin, setLogin ] = useState(false);
const openModalLogin = () => setLogin(true);
const closeModalLogin = () => setLogin(false);
const [showSignUp, setShow ] = useState(false);
const openModalSignUp = () => setShow(true);
const closeModalSignUp = () => setShow(false);
return (
<div className="bodyStart">
<img src="https://i.imgur.com/5gjRSmB.gif" alt="" id="bg" />
<div className="start_logo">
<img src={require("../styling/logo.png")} alt="" onClick={() => {
history.push('/home')
history.go(0)}} className="logo" />
</div>
<div className="start">
<div className="start_heading">
<h2>Mother Nature is Calling.</h2>
<h4>Find a place to recharge and escape the day to day.</h4>
</div>
<div className="start_location">
<p>Where?</p>
<div className="start_input">
<input type="text" placeholder="anywhere" />
<ArrowForwardIcon onClick={() => {
history.push('/search')
history.go(0)}}
className="arrow" fontSize="large"/>
</div>
</div>
<div className="start_authentication">
<Button className="login"
variant="contained"
color="primary"
size="large"
onClick={() => openModalLogin()}> Login </Button>
{showLogin && <LoginContent closeModal={closeModalLogin} show={showLogin} />}
<Button className="signup"
variant="contained"
size="large"
onClick={()=> openModalSignUp()}> Sign-Up </Button>
{showSignUp && <SignUpContent closeModal={closeModalSignUp} show={showSignUp} />}
</div>
</div>
</div>
)
}
I have made similar modals with Material-UI. You can change loginOpen state and signupOpen states in modals. See codepen below
Codepen
const { useState } = React;
const { Button, Dialog, DialogTitle, DialogContent, DialogActions } = MaterialUI;
function LoginDialog(props) {
const { open, setLoginOpen, setSignupOpen } = props;
const switchSignup = (event) => {
setLoginOpen(false)
setSignupOpen(true)
}
return (
<Dialog aria-labelledby="simple-dialog-title" open={open}>
<DialogTitle id="simple-dialog-title">LOGIN</DialogTitle>
<DialogContent>If you don't have an account, press SIGNUP</DialogContent>
<DialogActions>
<Button onClick={(event) => {setLoginOpen(false)}}>CLOSE</Button>
<Button>LOGIN</Button>
<Button onClick={switchSignup}>SIGNUP</Button>
</DialogActions>
</Dialog>
);
}
function SignupDialog(props) {
const { open, setLoginOpen, setSignupOpen } = props;
const switchLogin = (event) => {
setSignupOpen(false)
setLoginOpen(true)
}
return (
<Dialog aria-labelledby="simple-dialog-title" open={open}>
<DialogTitle id="simple-dialog-title">SIGNUP</DialogTitle>
<DialogContent>If you have an account, press LOGIN</DialogContent>
<DialogActions>
<Button onClick={(event) => {setSignupOpen(false)}}>CLOSE</Button>
<Button>SIGNUP</Button>
<Button onClick={switchLogin}>LOGIN</Button>
</DialogActions>
</Dialog>
);
}
const App = () => {
const [loginOpen, setLoginOpen] = useState(false)
const [signupOpen, setSignupOpen] = useState(false)
const handleLogin = (event) => {
setLoginOpen(true)
}
const handleSignup = (event) => {
setSignupOpen(true)
}
return (
<div>
<Button variant='contained' color='primary' onClick={handleLogin} >
LOGIN
</Button>
<Button variant='outlined' color='primary' onClick={handleSignup} >
SIGNUP
</Button>
<LoginDialog open={loginOpen} setLoginOpen={setLoginOpen} setSignupOpen={setSignupOpen} />
<SignupDialog open={signupOpen} setLoginOpen={setLoginOpen} setSignupOpen={setSignupOpen} />
</div>
)
}
ReactDOM.render(<App />, document.getElementById("root"));

react-modal - onChange on input is not updating state

I hope you will be able to help me with an answer to my question. I am using react-modal and inside the modal I have an input where users can write an email. When writing the email it should update the state but that is not happening.
What is happening right now is that the model re-renders every time I write a new letter and that results in the state only updating with the first letter I typed and then focus is lost.
I am using react hooks. I know that changes a bit.
My code looks like the following:
import React, { useState, useContext } from 'react';
import AppContext from '../../AppContext.jsx';
import GroupContext from './GroupContext.jsx';
import Section from '../../Elements/PageContent/Section.jsx';
import PageTitle from '../../Elements/PageContent/PageTitle.jsx';
import WhiteContainer from '../../Elements/PageContent/WhiteContainer.jsx';
import { Form, FormGroup, FormSection, FormSection_Split, Label, Input, Select, Submit } from '../../Elements/Forms/FormCollection.jsx';
import { MusicGenres } from '../../Elements/Forms/MusicGenres.jsx';
import { Years } from '../../Elements/Forms/Years.jsx';
import { H3 } from '../../Elements/Fonts/FontCollection.jsx';
import { Icon } from '../../Elements/Image/ImageUtil.jsx';
import ReactModal from "react-modal";
import { useModal } from "react-modal-hook";
export default function Groups(props) {
const AC = useContext(AppContext);
const GC = useContext(GroupContext);
const [groupName, setGroupName] = useState("");
const [groupDescription, setGroupDescription] = useState("");
const [memberEmail, setMemberEmail] = useState("");
const [groupMembers, setGroupMembers] = useState([]);
const [showModal, hideModal] = useModal(() => (
<ReactModal className="DialogPopup" isOpen ariaHideApp={false}>
<Form>
<FormGroup>
<FormSection>
<Label htmlFor="memberEmail" title="Email of your group member:" />
<Input type="email" name="memberEmail" value={memberEmail} onChange={(e) => setMemberEmail(e.target.value)} placeholder="#" />
</FormSection>
</FormGroup>
</Form>
<button onClick={(e) => hideModal()} className="Close" aria-label="Close popup"><Icon iconClass="fal fa-times" /></button>
</ReactModal>
), []);
async function addObjectToGroupMembersArray(e) {
e.preventDefault();
console.log("Adding member");
}
return (
<React.Fragment>
<PageTitle title="Add group" />
<Section>
<Form>
<FormGroup>
<FormSection>
<WhiteContainer>
<Label htmlFor="groupName" title="Group name:" />
<Input type="text" name="groupName" value={groupName} onChange={(e) => setGroupName(e.target.value)} maxLength="60" required />
<span className="CharactersLeft">Characters left: {60 - groupName.length}</span>
</WhiteContainer>
</FormSection>
<FormSection>
<WhiteContainer>
<Label htmlFor="groupDescription" title="Describe your group:" />
<textarea name="groupDescription" id="groupDescription" value={groupDescription} onChange={(e) => setGroupDescription(e.target.value)} maxLength="500"></textarea>
<span className="CharactersLeft">Characters left: {500 - groupDescription.length}</span>
</WhiteContainer>
</FormSection>
<FormSection>
<WhiteContainer>
<Label htmlFor="groupMembers" title="List the emails of your group members?" />
<a href="#" className="AddLink" aria-label="Add member" title="Click to add a member" onClick={(e) => { e.preventDefault(); showModal(); }}>
<Icon iconClass="fal fa-plus" />
</a>
</WhiteContainer>
</FormSection>
<FormSection className="FormSection--Submit">
<Submit text="Create group" />
</FormSection>
</FormGroup>
</Form>
</Section>
</React.Fragment>
);
}
Does anyone of you know why the modal is updating every time I type, resulting in not being able to write anything in the input. Should i use "ref" and if I should, how would I do that?
The onChange method I am using is always working, just not inside react-modal.
I finally figured it out. It's because modal is working a little like the useEffect hook. If i add memberEmail to the bottom of the modal state, then it is working.
const [memberEmail, setMemberEmail] = useState("");
const [showModal, hideModal] = useModal(() => (
<ReactModal className="DialogPopup" isOpen ariaHideApp={false}>
<Form>
<FormGroup>
<FormSection>
<Label htmlFor="memberEmail" title="Email of your group member:" />
<Input type="email" name="memberEmail" value={memberEmail} onChange={(e) => setMemberEmail(e.target.value)} placeholder="#" />
</FormSection>
</FormGroup>
</Form>
<button onClick={(e) => hideModal()} className="Close" aria-label="Close popup"><Icon iconClass="fal fa-times" /></button>
</ReactModal>
), [memberEmail]);
What about creating an external function that you would call in onChange?
something like:
const handleOnChange = (event) => {
setMemberEmail(event.target.value);
}
// then call it in your component
<Input type="email" name="memberEmail" value={memberEmail} onChange={handleOnChange} placeholder="#" />

How do I validate textfields in a dynamic array

I have one mother component and one child component. In the child component there are two textfields (name and email) and an add button. When the user presses on add a new set of the same textfields will be rendered. I save those textfields in my mother component in an array. I want to have a validate function that checks of the values are valid. If not i want to give the error props a true value so that the user can see that field is wrong. The only problem i have is figuring out how to give right textfield in the array the error value. Because now every textfield will get the error value.
Child Component:
import React from 'react';
import TextField from '#material-ui/core/TextField';
import AddIcon from '#material-ui/icons/Add';
import Minus from '#material-ui/icons/Delete';
import Button from '#material-ui/core/Button';
class People extends React.Component {
constructor(props){
super(props);
}
render(){
const {classes} = this.props;
return (
<div>
{this.props.people.map((person, index) => (
<div key={person}>
<div className="container">
<div className="row">
<div className="col s2">
<Button
mini
variant="fab"
color="primary"
aria-label="minus"
onClick={e =>
this.props.removeRow(index)}
data-toggle="tooltip"
>
<Minus/>
</Button>
</div>
<div>
<div className="col s5">
<TextField
name="name"
id="standard-dense"
label="Teamlid naam"
margin="dense"
value={person.name}
error={e =>
this.props.validate(e, index)}
onChange={e =>
this.props.onChange(e, index)}
/>
</div>
<div className="col s5">
<TextField
name="email"
id="standard-dense"
label="Teamlid email"
margin="dense"
value={person.email}
error={e =>
this.props.validate(e, index)}
onChange={e =>
this.props.onChange(e, index)}
/>
</div>
</div>
</div>
</div>
</div>
))}
<div className="container">
<div className="row">
<div className="col s2">
<Button
mini
variant="fab"
color="primary"
aria-label="Add"
onClick={this.props.addRow}
data-toggle="tooltip"
className="btn btn-xs btn-primary"
data-original-title="">
<AddIcon/>
</Button>
</div>
<div className="col s5">
</div>
<div className="col s5">
</div>
</div>
</div>
</div>
);
}
};
export default People;
Mother Component:
import React, {Component} from 'react';
import People from './People';
class Form extends React.Component{
constructor(props){
super(props);
this.state = {
people: []
}
}
addRow = () => {
this.setState(previousState => {
return {
people: [...previousState.people, {name: "", email: "", error:false}]
};
});
};
removeRow = index => {
this.setState(previousState => {
const people = [...previousState.people];
people.splice(index, 1);
return { people };
});
};
//onChange functie van de teamleden rijen
onChange = (event, index) => {
const { name, value } = event.target;
this.setState(previousState => {
const people = [...previousState.people];
people[index] = { ...people[index], [name]: value };
return { people };
});
};
validate = (event,index) => {
event.preventDefault();
if(!event.target.value){
return true;
}else{
return false;
}
};
render(){
const {classes} = this.props;
return(
<form>
<People
addRow={this.addRow}
removeRow={this.removeRow}
onChange={this.onChange}
people={this.state.people}
validate={this.validate}
/>
<button onClick={this.validate}>Validate</button>
</form>
);
}
}
export default Form;
I know that the validate function probably needs the index of the wrong textfield. But I don't know how to properly implement it.

Categories

Resources