lifting state up from child to parent, resets my parents states - reactjs

when I lift the state up to a parent it resets all my states in the parent component.
Parent Component
const [validName, setValidName] = useState(false);
const [validAddress, setValidAddress] = useState(false);
const [validPostal, setValidPostal] = useState(false);
const [validPhone, setValidPhone] = useState(false);
const [validEmail, setValidEmail] = useState(false);
const [validForm, setValidForm] = useState(false);
const isDisabled = (pWidth, pLength) => {
console.log("pWidth: " + pWidth);
console.log("pLength: " + pLength);
setSheetSize(pWidth, pLength);
console.log("in isDisabled!");
console.log(validName);
console.log(validAddress);
console.log(validPostal);
console.log(validPhone);
console.log(validEmail);
validateForm();
};
const setSheetSize = (width, length) => {
console.log("setSheetSize width: " + width);
console.log("setSheetSize length: " + length);
setLength(length);
setWidth(width);
};
const setRadiusSize = (radius) => {
setRadius(radius);
};
const [selectedOption, setSelectOption] = useState(
<SheetForm isDisabled={isDisabled} />
);
return (
<Col md={3}>
<div className="form-check mt-4">
<input
className="form-check-input"
type="radio"
name="cakeType"
id="sheet"
value="sheet"
checked={checkOption === "sheet"}
onClick={(e) => {
setCheckOption(e.target.value);
setSelectOption(<SheetForm isDisabled={isDisabled} />);
}}
/>
<label className="form-check-label" htmlFor="sheet">
Sheet Cake
</label>
</div>
</Col>
)
Child Component
import { useState } from "react";
const SheetForm = (props) => {
const [innerLength, setInnerLength] = useState();
const [innerWidth, setInnerWidth] = useState();
let isLengthGood = false;
let isWidthGood = false;
function validateSheetSize() {
if (innerLength >= 30 && innerLength <= 60) {
document.getElementById("length").classList.add("is-valid");
document.getElementById("length").classList.remove("is-invalid");
isLengthGood = true;
} else {
document.getElementById("length").classList.remove("is-valid");
document.getElementById("length").classList.add("is-invalid");
}
if (innerWidth >= 30 && innerWidth <= 45) {
document.getElementById("width").classList.add("is-valid");
document.getElementById("width").classList.remove("is-invalid");
isWidthGood = true;
} else {
document.getElementById("width").classList.remove("is-valid");
document.getElementById("width").classList.add("is-invalid");
}
if (isLengthGood && isWidthGood) {
console.log("everything good");
props.isDisabled(innerWidth, innerLength);
}
}
return (
<div id="sheetOption" className="mt-4">
<div className="input-group">
<span className="input-group-text">Sheet Size</span>
<input
onBlur={validateSheetSize}
id="length"
type="text"
aria-label="length"
className="form-control"
placeholder="min 30 max 60"
name="length"
min="30"
max="60"
required
onChange={(e) => {
setInnerLength(e.target.value);
}}
/>
<span className="input-group-text" id="basic-addon1">
L (cm)
</span>
<div className="valid-feedback">Looks good!</div>
<div className="invalid-feedback">
Length must be between 30cm and 60cm!
</div>
</div>
<div className="input-group">
<span className="input-group-text">Sheet Size</span>
<input
onBlur={validateSheetSize}
id="width"
type="text"
aria-label="width"
className="form-control"
placeholder="min 30 max 45"
name="width"
min="30"
max="45"
required
onChange={(e) => {
setInnerWidth(e.target.value);
}}
/>
<span className="input-group-text" id="basic-addon1">
W (cm)
</span>
<div className="valid-feedback">Looks good!</div>
<div className="invalid-feedback">
Width must be between 30cm and 45cm!
</div>
</div>
</div>
);
};
export default SheetForm;
I can lift the state back up to the parent and get the correct values, but when I check the states for validName, validAddress, validPostal, etc...
they all come back to the original setState of false.

Related

How to Validate Minimum Age Greater & Equal to 18 Reactjs

For the SignUp page I need to validate age is equal to or greater than 18. I have attempted using similar examples but all require me to install a dependency. I am looking for a way to achieve the desired results through React. My code is as follows
signup.jsx
import React from "react";
import { useState, useRef } from "react";
import { BsFillInfoCircleFill } from "react-icons/bs";
import Tooltip from "react-bootstrap/Tooltip";
import OverlayTrigger from "react-bootstrap/OverlayTrigger";
import { Link } from "react-router-dom";
import Alert from 'react-bootstrap/Alert'
import { UserAuth } from "../../AuthContext";
const Password = (props) =>
{
const [passwordShown, setPasswordShown] = useState(false);
const togglePassword = () => {
setPasswordShown(!passwordShown);
}
return(
<div className="input-group w-75 mb-5">
<input
type= {passwordShown ? 'text' : 'password'}
ref = {props.myRef}
className="form-control shadow-none"
placeholder="PSU1>OSU!"
aria-describedby="button-addon2"
></input>
<button onClick={togglePassword}>Show Password</button>
</div>
);
}
const SignUpPopup = (props) => {
//input fields
const firstName = useRef("");
const lastName = useRef("");
const email = useRef("");
const DOB = useRef("");
const password = useRef("");
const passwordConfirm = useRef("");
const [checked1, setChecked1] = useState(false);
const [checked2, setChecked2] = useState(false);
var errorMessage = ""
//change handlers
const handleChange1 = () => { setChecked1(!checked1) } ;
const handleChange2 = () => { setChecked2(!checked2) } ;
const [error, setError] = useState("");
const {createUser} = UserAuth();
//IMPROVE THE CHECKING OF THE FORM
function checkSignUp(){
var success = true
if (firstName.current.value === ""){
success = false
errorMessage += "Invalid first name\n"
}
if (lastName.current.value === ""){
success = false
errorMessage += "Invalid last name\n"
}
if (email.current.value === ""){
success = false
errorMessage += "Invalid email\n"
}
if (password.current.value === "" ){
success = false
errorMessage += "Invalid password\n"
}
if (!(passwordConfirm.current.value === password.current.value ) ){
success = false
errorMessage += "Passwords do not match\n"
}
return success;
}
async function addUserToDatabase(uid){
fetch("URL",{
method: "POST",
headers: { "Content-Type": "application/json"},
body: uid
})
}
async function handleSignup() {
setError("")
//if res == true, success, else failure and trigger alert
var res = checkSignUp();
if(res){
//authenticate
try{
await createUser(email.current.value, password.current.value);
const {user} = UserAuth();
addUserToDatabase(user.uid);
props.handleClose();
props.signupNextFunc();
}
catch(e){
errorMessage += "Invalid email or password"
setError(errorMessage)
}
}
}
const changeToLogin = ()=>{
props.handleClose()
props.loginFunc()
}
return (
<div className="popup-box">
<div className="box">
<div className="upperwrapper">
<span className="close-icon" onClick={props.handleClose}>
x
<input
type="text"
ref={firstName}
className="form-control shadow-none"
placeholder="Ben"
aria-describedby="button-addon2"
></input>
</div>
{/* LAST NAME INPUT */}
<p style={{ fontSize: "20px", marginTop: "15px" }}>
Last Name<span className="required-field"></span>
</p>
<div className="input-group w-75 mb-5">
<input
type="text"
ref = {lastName}
className="form-control shadow-none"
placeholder="Dover"
aria-describedby="button-addon2"
></input>
</div>
{/* EMAIL INPUT */}
<p style={{ fontSize: "20px", marginTop: "45px" }}>
Email<span className="required-field"></span>
</p>
<div className="input-group w-75 mb-5">
<input
type="text"
ref = {email}
className="form-control shadow-none"
placeholder="bendover#email.com"
aria-describedby="button-addon2"
></input>
</div>
<div className="d-flex bd-highlight mb-3 example-parent">
<p style={{ fontSize: "20px", marginTop: "10px" }}>
Date of Birth<span className="required-field"></span>
</p>
<div style={{ display: 'block', marginLeft: "-3px", marginTop: "-8px" }}
className="align-self-center p-2 bd-highlight col-example">
<OverlayTrigger
delay={{ hide: 450, show: 300 }}
overlay={(props) => (
<Tooltip {...props}>
Please provide your date of birth to validate...
</Tooltip>
)}
placement="right"
>
<div><BsFillInfoCircleFill /></div>
</OverlayTrigger>
</div>
</div>
<div className="input-group w-75 mb-5">
<input
type="date"
ref={DOB}
className="form-control shadow-none"
placeholder="mm/dd/yyyy"
aria-describedby="button-addon2"
></input>
</div>
)
};
export default SignUpPopup;
Any help or guidance to the right path is greatly appreciated!
You can validate age on onChange of input
const onChange = (e) => {
const currentYear = new Date().getFullYear();
const year = e.target.value.split("-")[0];
const age = currentYear - year;
if (age < 18) setError("Invalid age");
}
<input
type="date"
className="form-control shadow-none"
placeholder="mm/dd/yyyy"
aria-describedby="button-addon2"
onChange={onChange}
/>

MERN: best way to validate an Autocomplete control

I'm working on user input validation, I'm having problems with the Autocomplete, so far I'm focus on evaluate if the associated TextField is empty, this is the code snippet:
<div className={clientMethodPaymentControlClasses}>
<label htmlFor="clientMethodPayment">Method of Payment *</label>
<Autocomplete
options={paymentMethods}
style={{ width: 300 }}
autoHighlight
renderInput={(params) => (
<TextField
id="clientMethodPayment"
{...params}
variant="outlined"
autocomplete="off"
ref={clientMethodPaymentRef}
/>
)}
/>
{!formInputsValidity.clientMethodPayment && (
<p>Please choose a method of payment</p>
)}
</div>
I try to catch the control's value using these lines:
const isEmpty = (value) => value.trim() === "";
....
const enteredClientMethodPaymentIsValid = !isEmpty(
enteredClientMethodPayment
);
During the execution I'm getting the error: Uncaught TypeError: value is undefined (related to const isEmpty).
This is the entire code of the component:
import { useRef, useState } from "react";
import TextField from "#material-ui/core/TextField";
import Autocomplete from "#material-ui/lab/Autocomplete";
import classes from "./Orderdetails.module.css";
const isEmpty = (value) => value.trim() === "";
const isNotNineChars = (value) => value.trim().length !== 9;
const paymentMethods = ["Cash", "Credit", "Crypto"];
const OrderDetails = (props) => {
const [formInputsValidity, setFormInputsValidity] = useState({
clientName: true,
clientCellPhone: true,
streetDeliveryAddress: true,
cityDeliveryAddress: true,
postalCodeDeliveryAddress: true,
ordersDeliveryAddress: true,
clientMethodPayment: true,
});
//estos objetos sirven para no capturar todos los keystrokes durante dataInput
const clientNameRef = useRef();
const clientCellPhoneRef = useRef();
const streetDeliveryAddressRef = useRef();
const cityDeliveryAddressRef = useRef();
const postalCodeDeliveryAddressRef = useRef();
const ordersDeliveryAddressRef = useRef();
const clientMethodPaymentRef = useRef();
const ConfirmHandler = (event) => {
event.preventDefault();
const enteredName = clientNameRef.current.value;
const enteredCellPhone = clientCellPhoneRef.current.value;
const enteredOrdersDeliveryAddress = ordersDeliveryAddressRef.current.value;
const enteredStreetDeliveryAddress = streetDeliveryAddressRef.current.value;
const enteredCityDeliveryAddress = cityDeliveryAddressRef.current.value;
const enteredPostalCodeDeliveryAddress =
postalCodeDeliveryAddressRef.current.value;
const enteredClientMethodPayment = clientMethodPaymentRef.current.value;
const enteredNameIsValid = !isEmpty(enteredName);
const enteredCellPhoneIsValid = !isNotNineChars(enteredCellPhone);
const enteredOrdersDeliveryAddressIsValid = !isEmpty(
enteredOrdersDeliveryAddress
);
const enteredStreetDeliveryAddressIsValid = !isEmpty(
enteredStreetDeliveryAddress
);
const enteredCityDeliveryAddressIsValid = !isEmpty(
enteredCityDeliveryAddress
);
const enteredPostalCodeDeliveryAddressIsValid = !isEmpty(
enteredPostalCodeDeliveryAddress
);
const enteredClientMethodPaymentIsValid = !isEmpty(
enteredClientMethodPayment
);
setFormInputsValidity({
clientName: enteredNameIsValid,
clientCellPhone: enteredCellPhoneIsValid,
ordersDeliveryAddress: enteredOrdersDeliveryAddressIsValid,
streetDeliveryAddress: enteredStreetDeliveryAddressIsValid,
cityDeliveryAddress: enteredCityDeliveryAddressIsValid,
postalCodeDeliveryAddress: enteredPostalCodeDeliveryAddressIsValid,
clientMethodPayment: enteredClientMethodPaymentIsValid,
});
const formIsValid =
enteredNameIsValid &&
enteredCellPhoneIsValid &&
enteredOrdersDeliveryAddressIsValid &&
enteredStreetDeliveryAddressIsValid &&
enteredCityDeliveryAddressIsValid &&
enteredPostalCodeDeliveryAddressIsValid &&
enteredClientMethodPayment;
if (!formIsValid) {
return;
}
props.onConfirm({
clientName: enteredName,
clientCellPhone: enteredCellPhone,
ordersDeliveryAddress: enteredOrdersDeliveryAddress,
streetDeliveryAddress: enteredStreetDeliveryAddress,
cityDeliveryAddress: enteredCityDeliveryAddress,
postalCodeDeliveryAddress: enteredPostalCodeDeliveryAddress,
clientMethodPayment: enteredClientMethodPayment,
});
};
const nameControlClasses = `${classes.control} ${
formInputsValidity.clientName ? "" : classes.invalid
}`;
const phoneControlClasses = `${classes.control} ${
formInputsValidity.clientCellPhone ? "" : classes.invalid
}`;
const delivAddressControlClasses = `${classes.control} ${
formInputsValidity.ordersDeliveryAddress ? "" : classes.invalid
}`;
const cityDeliveryAddressControlClasses = `${classes.control} ${
formInputsValidity.cityDeliveryAddress ? "" : classes.invalid
}`;
const streetDeliveryAddressControlClasses = `${classes.control} ${
formInputsValidity.streetDeliveryAddress ? "" : classes.invalid
}`;
const postalCodeDeliveryAddressControlClasses = `${classes.control} ${
formInputsValidity.postalCodeDeliveryAddress ? "" : classes.invalid
}`;
const clientMethodPaymentControlClasses = `${classes.control} ${
formInputsValidity.clientMethodPayment ? "" : classes.invalid
}`;
return (
<form className={classes.form} onSubmit={ConfirmHandler}>
<div className={nameControlClasses}>
<label htmlFor="clientName">Client's Name</label>
<input
type="text"
autoComplete="off"
id="clientName"
ref={clientNameRef}
/>
{!formInputsValidity.clientName && <p>Please Enter a valid Name</p>}
</div>
<div className={phoneControlClasses}>
<label htmlFor="clientCellPhone">Client's Cell Phone Number</label>
<input
type="text"
id="clientCellPhone"
autocomplete="off"
ref={clientCellPhoneRef}
/>
{!formInputsValidity.clientCellPhone && (
<p>Please Enter a 8 digits numbers</p>
)}
</div>
<div className={delivAddressControlClasses}>
<label htmlFor="ordersDeliveryAddress">Delivery Address *</label>
<input
type="text"
id="ordersDeliveryAddress"
autocomplete="off"
ref={ordersDeliveryAddressRef}
/>
{!formInputsValidity.ordersDeliveryAddress && (
<p>Please Enter a valid address</p>
)}
</div>
<div className={cityDeliveryAddressControlClasses}>
<label htmlFor="cityDeliveryAddress">City Delivery Address *</label>
<input
type="text"
id="cityDeliveryAddress"
autocomplete="off"
ref={cityDeliveryAddressRef}
/>
{!formInputsValidity.cityDeliveryAddress && (
<p>Please Enter a valid city name</p>
)}
</div>
<div className={streetDeliveryAddressControlClasses}>
<label htmlFor="streetDeliveryAddress">Street Delivery Address *</label>
<input
type="text"
id="streetDeliveryAddress"
autocomplete="off"
ref={streetDeliveryAddressRef}
/>
{!formInputsValidity.streetDeliveryAddress && (
<p>Please Enter a valid street name</p>
)}
</div>
<div className={postalCodeDeliveryAddressControlClasses}>
<label htmlFor="postalCodeDeliveryAddress">
Postal Code Delivery Address *
</label>
<input
type="text"
id="postalCodeDeliveryAddress"
autocomplete="off"
ref={postalCodeDeliveryAddressRef}
/>
{!formInputsValidity.postalCodeDeliveryAddress && (
<p>Please Enter a valid Postal Code</p>
)}
</div>
<div className={clientMethodPaymentControlClasses}>
<label htmlFor="clientMethodPayment">Method of Payment *</label>
<Autocomplete
options={paymentMethods}
style={{ width: 300 }}
autoHighlight
renderInput={(params) => (
<TextField
id="clientMethodPayment"
{...params}
variant="outlined"
autocomplete="off"
ref={clientMethodPaymentRef}
/>
)}
/>
{!formInputsValidity.clientMethodPayment && (
<p>Please choose a method of payment</p>
)}
</div>
<div className={classes.actions}>
<button type="button" onClick={props.onCancel}>
Close
</button>
<button>Confirm Order</button>
</div>
</form>
);
};
export default OrderDetails;
My questions are:
is it a good approach trying to validate the related Textfield of Autocomplete?
what should be the best way to validate if the Autocomplete control is Empty?
Thanks in advance.

react simple keyboard not able to type in multiple input

I have following code of Calculator.jsx where everything looks fine.The main thing I want to achieve is keyboard to displayed only on input click which is done but the keyboard does not seem to type though the following code looks fine. Are there any other way to show/hide keyboard only on input click as well as make keyboard be able to type. My code for Calculator.jsx is
Calculator.jsx
import React, { useState, useRef, useEffect } from 'react';
import './Calculator.css'
import { Link } from 'react-router-dom';
import Keyboard from "react-simple-keyboard";
import "react-simple-keyboard/build/css/index.css";
const Calculator = () => {
const [inputs, setInputs] = useState({});
const [layoutName, setLayoutName] = useState("default");
const [inputName, setInputName] = useState("default");
const keyboard = useRef();
const [keyboardVisibility, setKeyboardVisibility] = useState(false);
useEffect(() => {
function clickHanlder(e) {
if (
!(e.target.nodeName === "INPUT") &&
!e.target.classList.contains("hg-button") &&
!e.target.classList.contains("hg-row")
) {
setKeyboardVisibility(false);
}
}
window.addEventListener("click", clickHanlder);
return window.removeEventListener("click", clickHanlder, true);
}, []);
const onChangeAll = inputs => {
setInputs({ ...inputs });
console.log("Inputs changed", inputs);
};
const handleShift = () => {
const newLayoutName = layoutName === "default" ? "shift" : "default";
setLayoutName(newLayoutName);
};
const onKeyPress = button => {
console.log("Button pressed", button);
if (button === "{shift}" || button === "{lock}") handleShift();
};
const onChangeInput = event => {
const inputVal = event.target.value;
setInputs({
...inputs,
[inputName]: inputVal
});
keyboard.current.setInput(inputVal);
};
const getInputValue = inputName => {
return inputs[inputName] || "";
};
return (
<div>
<div className="bg">
<div className="deposit">
<div className="header">
<h1>Deposit Calculator</h1>
<div className="form">
<form className="calculator">
<div className="form-group">
<label for="depositAmount">Deposit Amount:</label>
<span className="rupees">Rs</span>
<input className="IInput"
type="text"
name='depositAmount'
placeholder='0'
value={getInputValue("depositAmount")}
onChange={onChangeInput}
onFocus={() => {
setKeyboardVisibility(true);
setInputName("depositAmount")
}}
/>
</div>
<div className="form-group">
<label for="interestRate">Interest Rate:</label>
<input className= "IIinput"
type="text"
name='Interest'
placeholder='0'
value={getInputValue("interestRate")}
onChange={onChangeInput}
onFocus={() => {
setKeyboardVisibility(true);
setInputName("interestRate")
}}
/>
<span className= "percent">%</span>
</div>
<div class="form-group">
<label for="Tenure">Tenure:</label>
<input className="Input"
type='number'
min='1'
max='5'
name='tenure'
placeholder='1 year'
value={getInputValue("tenure")}
onChange={onChangeInput}
onFocus={() => {
setKeyboardVisibility(true);
setInputName("tenure")
}}
/>
</div>
{ keyboardVisibility && (
<Keyboard
keyboardRef={(r) => (keyboard.current = r)}
layoutName={layoutName}
onChange={onChangeAll}
onKeyPress={onKeyPress}
/>
)}
</form>
<button className="calculate">Calculate
</button>
</div>
<div className="given">
<p >
Total Deposit: Rs 0
</p>
<p>
Interest: Rs 0
</p>
<p>
Maturity Amount: Rs 0
</p>
</div>
</div>
</div>
</div>
<Link to="/">
<button className="Back">
<i class="fas fa-angle-double-left"></i>
</button>
</Link>
</div>
);
};
export default Calculator;
You are setting the inputs state by spreading input string from keyboard onChangeAll into an object setInputs({ ...inputs }). If I enter ab it will set as {0: "a", 1:"b"}.
Update the onChange prop in Keyboard to onChangeAll and pass inputName prop with your inputName state value. Read react-simple-keyboard DOCS.
onChangeAll
const onChangeAll = (inputs) => {
console.log("Inputs changed", inputs);
setInputs(inputs);
};
Keyboard
{keyboardVisibility && (
<Keyboard
keyboardRef={(r) => (keyboard.current = r)}
layoutName={layoutName}
onChangeAll={onChangeAll}
onKeyPress={onKeyPress}
inputName={inputName}
/>
)}
CodeSandbox link

How to get each item's value in React.js

const [state, setState] = useState("");
<input onChange={e=>setState(e.target.value)}
I know that I can use onChange={} to get each value but I want to get the
(shirts x pants x shoes) when a button onClick={} event happens
function Somethingie() {
return (
<div>
Shirts: <input className="one" type="number"></input>
Pants: <input className="two" type="number"></input>
Shoes: <input className="three" type="number"></input>
<br /> <br />
<button
onClick={() => {
console.log(
document.querySelector(".one").value *
document.querySelector(".two").value *
document.querySelector(".three").value
);
}}
>
Calculate!
</button>
<br /> <br />
Amount of Possible Outfits: <h1 className="result"></h1>
</div>
);
}
ReactDOM.render(
<Somethingie />,
document.getElementById("root")
);
or do I create an async function?
I would create a state for each input, set the value of the respective input to this state, set the state for each input onChange, and finally, in the onClick of the button just combine the three states.
Example input:
const [state1, setState1] = useState("")
...
const change1 = (e) => {
setState1(e.target.value);
}
...
<input className="one" type="number" value={state1} onChange={change1}/>
onClick of the button
const handleClick = () => {
result = state1 * state2 * state3;
}
function Somethingie() {
return (
<div>
Shirts: <input className="one" type="number"></input>
Pants: <input className="two" type="number"></input>
Shoes: <input className="three" type="number"></input>
<br /> <br />
<button
onClick={() => {
let x = document.getElementsByClassName('result');
x[0].innerHTML =
document.querySelector('.one').value *
document.querySelector('.two').value *
document.querySelector('.three').value;
}}
>
Calculate!
</button>
<br /> <br />
Amount of Possible Outfits: <h1 className="result"></h1>
</div>
);}
ReactDOM.render(
<Somethingie />,
document.getElementById("root")
);
You can directly place calculated value as shown in above code snippet.
You need to keep each of the data in its own useState like this:
import { useState } from "react";
const Combinations = () => {
const [shirts, setShirts] = useState(0);
const [pants, setPants] = useState(0);
const [shoes, setShoes] = useState(0);
const [total, setTotal] = useState(0);
const onChange = (e) => {
console.log(e);
console.log(typeof e.target.value);
console.log(Number(e.target.value));
if (e.target.name === "shirts") setShirts(Number(e.target.value));
if (e.target.name === "pants") setPants(Number(e.target.value));
if (e.target.name === "shoes") setShoes(Number(e.target.value));
};
const calculate = () => {
let all = null;
if (shirts !== 0) {
if (all === null) {
all = shirts;
} else {
all *= shirts;
}
}
if (pants !== 0) {
if (all === null) {
all = pants;
} else {
all *= pants;
}
}
if (shoes !== 0) {
if (all === null) {
all = shoes;
} else {
all *= shoes;
}
}
setTotal(all);
};
return (
<div>
<label htmlFor="shirts">Shirts: </label>
<input
type="number"
id="shirts"
name="shirts"
value={shirts}
onChange={onChange}
/>
<br />
<label htmlFor="pants">Pants: </label>
<input
type="number"
id="pants"
name="pants"
value={pants}
onChange={onChange}
/>
<br />
<label htmlFor="shoes">Shoes: </label>
<input
type="number"
id="shoes"
name="shoes"
value={shoes}
onChange={onChange}
/>
<br />
<button onClick={calculate}>Calculate!</button>
<br />
<p>Amount of Possible Outfits: {total}</p>
</div>
);
}

How do i limit the list of data being rendered for a particular list in react js

I'm trying to create an app that when the user clicks on create button a survey question with four answers gets created. The goal is that in a single list the user can maximum add up to 4 questions and a minimum of 1 question. So when the user tries to add another question after the 4th question a new survey list should be created. So one survey list can contain a maximum of four questions.
//Survey.js
import React, { useState, useEffect } from "react";
import { Fragment } from "react";
import "./Survey.css";
import CreateSurvey from "../modals/CreateSurvey";
import Card from "../card/Card";
const Survey = () => {
const [modal, setModal] = useState(false);
const [surveyList, setSurveyList] = useState([]);
useEffect(() => {
let arr = localStorage.getItem("surveyList");
if (arr) {
let obj = JSON.parse(arr);
setSurveyList(obj);
}
}, []);
// const surveyListArray = [];
// while (surveyList.length > 0) {
// surveyListArray.push(surveyList.splice(0, 3));
// }
const deleteSurvey = (index) => {
let tempList = surveyList;
tempList.splice(index, 1);
localStorage.setItem("surveyList", JSON.stringify(tempList));
setSurveyList(tempList);
window.location.reload();
};
const toggle = () => {
setModal(!modal);
};
const updateListArray = (obj, index) => {
let tempList = surveyList;
tempList[index] = obj;
localStorage.setItem("surveyList", JSON.stringify(tempList));
setSurveyList(tempList);
window.location.reload();
};
const saveSurvey = (surveyObj) => {
let tempList = surveyList;
tempList.push(surveyObj);
localStorage.setItem("surveyList", JSON.stringify(tempList));
setSurveyList(surveyList);
setModal(false);
};
return (
<Fragment>
<div className="header text-center">
<h5>Survey</h5>
<button className="btn btn-primary" onClick={() => setModal(true)}>
Create Survey
</button>
</div>
<div className="survey-container">
{surveyList &&
surveyList.map((obj, index) => (
<Card
surveyObj={obj}
index={index}
deleteSurvey={deleteSurvey}
updateListArray={updateListArray}
>
<input type="radio" name="answerOne" />
</Card>
))}
</div>
<CreateSurvey toggle={toggle} modal={modal} save={saveSurvey} />
</Fragment>
);
};
export default Survey;
//Card.js
import React, { useState } from "react";
import "./Card.css";
import EditSurvey from "../modals/EditSurvey";
const Card = ({ surveyObj, deleteSurvey, index, updateListArray }) => {
const [modal, setModal] = useState(false);
const toggle = () => {
setModal(!modal);
};
const updateSurvey = (obj) => {
updateListArray(obj, index);
};
const deleteHandler = () => {
deleteSurvey(index);
};
return (
<div>
<div className="card-wrapper mr-5">
<div className="card-top"></div>
<div className="survey-holder">
<span className="card-headers">{surveyObj.name}</span>
<span className="check">
<input type="radio" className="radio" />
<p className="answer"> {surveyObj.answerOne}</p>
</span>
<span className="check">
<input type="radio" className="radio" />
<p className="answer"> {surveyObj.answerTwo}</p>
</span>
<span className="check">
<input type="radio" className="radio" />
<p className="answer"> {surveyObj.answerThree}</p>
</span>
<span className="check">
<input type="radio" className="radio" />
<p className="answer"> {surveyObj.answerFour}</p>
</span>
<div className="icons">
<i className="far fa-edit edit" onClick={() => setModal(true)}></i>
<i className="fas fa-trash-alt delete" onClick={deleteHandler}></i>
</div>
</div>
<EditSurvey
modal={modal}
toggle={toggle}
updateSurvey={updateSurvey}
surveyObj={surveyObj}
/>
</div>
</div>
);
};
export default Card;
//CreateSurvey.js
import React, { useState } from "react";
import { Button, Modal, ModalHeader, ModalBody, ModalFooter } from "reactstrap";
import { Fragment } from "react";
const CreateSurvey = ({ modal, toggle, save }) => {
const [question, setQuestion] = useState("");
const [answerOne, setAnswerOne] = useState("");
const [answerTwo, setAnswerTwo] = useState("");
const [answerThree, setAnswerThree] = useState("");
const [answerFour, setAnswerFour] = useState("");
const changeHandler = (e) => {
const { name, value } = e.target;
if (name === "question") {
setQuestion(value);
} else if (name === "answerOne") {
setAnswerOne(value);
} else if (name === "answerTwo") {
setAnswerTwo(value);
} else if (name === "answerThree") {
setAnswerThree(value);
} else {
setAnswerFour(value);
}
};
const saveHandler = (e) => {
e.preventDefault();
let surveyObj = {};
surveyObj["name"] = question;
surveyObj["answerOne"] = answerOne;
surveyObj["answerTwo"] = answerTwo;
surveyObj["answerThree"] = answerThree;
surveyObj["answerFour"] = answerFour;
save(surveyObj);
};
return (
<Fragment>
<Modal isOpen={modal} toggle={toggle}>
<ModalHeader toggle={toggle}>Create a Survey Question</ModalHeader>
<ModalBody>
<form>
<div>
<div className="form-group">
<label>Survey Questions</label>
<input
type="text"
className="form-control"
value={question}
name="question"
onChange={changeHandler}
/>
</div>
</div>
<div className="mt-2">
<label>Survey Answers</label>
<div className="form-group">
<label>Answer 1</label>
<input
type="text"
className="form-control mt-2 mb-2"
value={answerOne}
name="answerOne"
onChange={changeHandler}
/>
</div>
<div className="form-group">
<label>Answer 2</label>
<input
type="text"
className="form-control mt-2 mb-2"
value={answerTwo}
name="answerTwo"
onChange={changeHandler}
/>
</div>
<div className="form-group">
<label>Answer 3</label>
<input
type="text"
className="form-control mt-2 mb-2"
value={answerThree}
name="answerThree"
onChange={changeHandler}
/>
</div>
<div className="form-group">
<label>Answer 4</label>
<input
type="text"
className="form-control mt-2 mb-2"
value={answerFour}
name="answerFour"
onChange={changeHandler}
/>
</div>
</div>
</form>
</ModalBody>
<ModalFooter>
<Button color="primary" onClick={saveHandler}>
Create
</Button>
<Button color="secondary" onClick={toggle}>
Cancel
</Button>
</ModalFooter>
</Modal>
</Fragment>
);
};
export default CreateSurvey;

Resources