Hi in my application we are using initialstate where the application sample data will be defined and using the context for state management, below is my sample initial state:
-
creditCard: {
isSaved: false,
lastFourDigits: "1235",
loading: false,
cardholder: "",
cardnumber: "",
cardmonth: "",
cardyear: "",
cardcvv: "",
},
etc:{}....
and in my component i am using usestate for setting the data as below :
const { state } = useContext(StateContext);
const [cardholder, setcardholder] = useState("");
const [cardnumber, setcardnumber] = useState("");
const [cardmonth, setcardmonth] = useState("");
const [cardyear, setcardyear] = useState("");
const [cardcvv, setcardcvv] = useState("");
and in onchange i am setting state as below:
<TextField
name="cardmonth"
label="MM"
error={errors.cardmonth}
value={cardmonth}
onChange={onChange}
onBlur={validateInput}
helperText={errors.cardmonth && "Invalid month"}
className={classes.expiryDateInputs}
/>
onchange=()=>{
let cardMonth = /^0[1-9]|1[0-2]/.test(e.target.value);
if (cardMonth === true) {
setcardmonth(e.target.value.replace(/\D/g, "").slice(0, 2));
setErrors({ ...errors, cardmonth: false });
} else {
setErrors({ ...errors, cardmonth: true });
}
if (state.creditCard.cardyear !== "") {
validateExpiryDate();
}
}
is this the correct way what i am doing, can anyone please tell me what i am doing in onchange and in html code is correct or not..
CodePudding user response:
If you need to validate your input inside onChange
this code is perfectly fine.
But ,It's not a good idea to validate input on the onChange
event . Put your validation logic inside onBlur
or onSubmit
events and in onChange
event , simply set state to event value.
also, I would recommend better naming convention.
onChange={(e)=>handleOnChange(e)}
///////////
handleOnChange=(event)=>{
setcardmonth(event.target.value);
}
// move your validation logic to onBlur or onSubmit
CodePudding user response:
Seems like you have defined your initialState
up on the context/global level, but at the same time redefined it in one of your local component with a bunch more individual state:
const { state } = useContext(StateContext);
const [cardholder, setcardholder] = useState("");
const [cardnumber, setcardnumber] = useState("");
const [cardmonth, setcardmonth] = useState("");
const [cardyear, setcardyear] = useState("");
const [cardcvv, setcardcvv] = useState("");
That effectly makes your onChange
function only update the state you redefined in your component, and it does not affect your context state, and won't update UI if the UI is dependent on context state.:
onchange=()=>{
let cardMonth = /^0[1-9]|1[0-2]/.test(e.target.value);
if (cardMonth === true) {
setcardmonth(e.target.value.replace(/\D/g, "").slice(0, 2));
setErrors({ ...errors, cardmonth: false });
} else {
setErrors({ ...errors, cardmonth: true });
}
if (state.creditCard.cardyear !== "") {
validateExpiryDate();
}
Meaning you are doing some extra unnecessary work by simplying redefinning things/states.
You can do one of the three ways:
- Go straight for local state without global state, and if some child components needs them, you can just pass props and drill them down;
- Or combine global and local state: for those states that need to be shared between different non-related components, you define it in global level, ie. your
initialstate
, for those that doesn't, put them in a local state; - Or go straight for global state.
On the straight global state approach, you can combine useReducer
with context
, and that makes updating state more managable(considering your initialstate
is relatively complex), otherwise, you can pass setState function:
const { state, setState } = useContext(StateContext); // <- pass down setState from context as well
onchange=()=>{
let cardMonth = /^0[1-9]|1[0-2]/.test(e.target.value);
if (cardMonth === true) {
setState(); // <- your update logic
} else {
setState(); // <- your update logic
}
if (state.creditCard.cardyear !== "") {
validateExpiryDate();
}