简体   繁体   English

反应:state 变量不变,setState 未触发

[英]React: state variable is unchanged, setState is not triggering

Here is my code.这是我的代码。 The confirm state variable on line 34 will not change.第 34 行的confirm state 变量不会改变。 Calling setConfirm from handleSubmit does not change it.handleSubmit调用setConfirm不会改变它。 I've attempted deliberately toggling it in dev tools, no effect.我试图故意在开发工具中切换它,没有效果。 I've tried deliberately setting it to true in the code, and placing {confirm && <h1>TEST</h1>} at the top of the contact form.我尝试在代码中故意将其设置为 true,并将{confirm && <h1>TEST</h1>}放在联系表单的顶部。 It doesn't render the h1, even when deliberately set to true.即使故意设置为 true,它也不会呈现 h1。 But {true && <h1>TEST</h1>} works just fine.但是{true && <h1>TEST</h1>}工作得很好。 It's as if the confirm variable doesn't even exist.就好像confirm变量甚至不存在一样。 Can someone shed some light on why this might be happening?有人可以解释为什么会发生这种情况吗?

import { useState, useEffect } from 'react'
import styles from "./ContactAndBooking.module.css"

const ContactAndBooking = () => {
    // Contact form values
    const [contact, setContact] = useState({
        name: null,
        email: null,
        phone: null,
        reason: null,
        message: null
    })

    // Booking form values
    const [booking, setBooking] = useState({
        name: null,
        email: null,
        phone: null,
        date: null,
        time: null,
        description: null
    })

    // Store today's date, calendar selection minimum
    const [minDate, setMinDate] = useState()

    // Display contact form or booking form, switch on button press
    const [typeContact, setTypeContact] = useState("contact")

    // Flag invalid form values for validation alerts
    const [validFlag, setValidFlag] = useState(true)

    // Successful message confirmation flag
    const [confirm, setConfirm] = useState(false)

    // Keep track of today's date, booking calendar selection minimum
    useEffect(()=> {
        let today = new Date
        let dd = today.getDate()
        let mm = today.getMonth() + 1
        let yyyy = today.getFullYear()

        if (dd < 10)
            dd = '0' + dd
        if (mm < 10)
            mm = '0' + mm

        today = yyyy + '-' + mm + '-' + dd
        setMinDate(today)
    })

    // Validate form values
    const validate = () => {
        // Track and return form validity, switch to false if any field fails
        let isValid = true

        // Check validity of contact form values
        if (typeContact === "contact"){
            // If no name, trigger invalid flag
            if (!contact.name){
                isValid = false
            }
            // If no email or email does not match regex, trigger invalid flag
            if (!contact.email || !contact.email.match(/^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/)){
                isValid = false
            }
            // If phone number length is neither 10 nor 11 digits long, trigger invalid flag
            if (!contact.phone || ![10,11].includes(contact.phone.split('-').join('').split('').length) || contact.phone.split('-').join('').split('').some(e => !'0123456789'.includes(e))){
                isValid = false
            }
            // If no reason for contact is given, trigger invalid flag
            if (!contact.reason){
                isValid = false
            }
            // If message field is blank, trigger invalid flag
            if (!contact.message){
                isValid = false
            }
        }
        // Check validity of booking form values
        else if (typeContact === "booking"){
            // If no name, trigger invalid flag
            if (!booking.name){
                isValid = false
            }
            // If no email or email does not match regex, trigger invalid flag
            if (!booking.email || !booking.email.match(/^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/)){
                isValid = false
            }
            // If phone number length is neither 10 nor 11 digits long, trigger invalid flag
            if (!booking.phone || ![10,11].includes(booking.phone.split('-').join('').split('').length)|| booking.phone.split('-').join('').split('').some(e => !'0123456789'.includes(e))){
                isValid = false
            }
            // If no booking date is selected, trigger invalid flag
            if (!booking.date){
                isValid = false
            }
            // If no booking time is selected, trigger invalid flag
            if (!booking.time){
                isValid = false
            }
            // If no booking description is given, trigger invalid flag
            if (!booking.description){
                isValid = false
            }
        }

        // set form validation alert flag on validation failure
        !isValid ? setValidFlag(false) : setValidFlag(true)

        return isValid
    }

    const handleSubmit = (e) => {
        e.preventDefault()
        setValidFlag(true)
        if (validate()){
            console.log("CONFIRMATION TRIGGERING...") // TESTING
            // Trigger confirmation window
            setConfirm(true) // NOT TRIGGERING
            console.log("CONFIRMATION TRIGGERED") // TESTING
            if (typeContact === "contact"){
                // To be replaced with Axios request
                console.log(contact)
            }
            else if (typeContact === "booking"){
                // To be replaced with Axios request
                console.log(booking)
            }
        }
        // set form validation alert flag on validation failure
        else {
            setValidFlag(false)
            console.log("SUBMISSION INVALID")
        }
    }

    // Contact form view
    const contactWindow = () => {
        return (
            <form onSubmit={e => handleSubmit(e)}>
                {confirm && <h1>TEST</h1>}
                <label className={styles.label} htmlFor="name">Name: </label>
                <input 
                    className={styles.input} 
                    name="name" 
                    type="text" 
                    onChange={e => setContact({...contact, name: e.target.value})} 
                />
                <span className={!validFlag && !contact.name ? styles.warning : styles.warningHidden}>Please enter your name.</span>
                <label className={styles.label} htmlFor="email">Email: </label>
                <input 
                    className={styles.input} 
                    name="email" 
                    type="email" 
                    onChange={e => setContact({...contact, email: e.target.value})} 
                />
                <span className={
                    !validFlag && (!contact.email || !contact.email.match(/^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/))
                    ? styles.warning
                    : styles.warningHidden
                }>
                    Please enter a valid email address.
                </span>
                <label className={styles.label} htmlFor="phone">Phone: </label>
                <input 
                    className={styles.input} 
                    name="phone" 
                    type="text" 
                    onChange={e => setContact({...contact, phone: e.target.value})} 
                />
                <span className={
                    !validFlag && (!contact.phone || ![10,11].includes(contact.phone.split('-').join('').split('').length) || contact.phone.split('-').join('').split('').some(e => !'0123456789'.includes(e)))
                    ? styles.warning
                    : styles.warningHidden
                }>Please enter a valid phone number.</span>}
                <select 
                    className={styles.select} 
                    onChange={e => setContact({...contact, reason: e.target.value})}
                    defaultValue="Reason for contact"
                >
                    <option className={styles.option} value="Reason for contact" disabled>Reason for contact</option>
                    <option className={styles.option} value="Business Inquiry">Business Inquiry</option>
                    <option className={styles.option} value="Ticket Sales">Ticket Sales</option>
                    <option className={styles.option} value="Other">Other</option>
                </select>
                <span className={!validFlag && !contact.reason ? styles.warning : styles.warningHidden}>Please select a reason for contact.</span>
                <textarea 
                    className={`${styles.textarea} ${styles.textareaContact}`} 
                    placeholder="How can I help you?" 
                    onChange={e => setContact({...contact, message: e.target.value})} 
                />
                <span className={!validFlag && !contact.message ? styles.warning : styles.warningHideen}>Please enter your message.</span>
                <button className={styles.submit} role="submit">Submit</button>
            </form>
        )
    }

    // Booking form view
    const bookingWindow = () => {
        return (
            <form onSubmit={handleSubmit}>
                <label className={styles.label} htmlFor="name">Name: </label>
                <input 
                    className={styles.input} 
                    name="name" 
                    type="text" 
                    onChange={e => setBooking({...booking, name: e.target.value})} 
                />
                <span className={!validFlag && !booking.name ? styles.warning : styles.warningHidden}>Please enter your name.</span>
                <label className={styles.label} htmlFor="email">Email: </label>
                <input 
                    className={styles.input} 
                    name="email" 
                    type="email" 
                    onChange={e => setBooking({...booking, email: e.target.value})} 
                />
                <span className={
                    !validFlag && (!booking.email || !booking.email.match(/^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/))
                    ? styles.warning
                    : styles.warningHidden
                }>
                    Please enter a valid email address.
                </span>
                <label className={styles.label} htmlFor="phone">Phone: </label>
                <input 
                    className={styles.input} 
                    name="phone" 
                    type="text" 
                    onChange={e => setBooking({...booking, phone: e.target.value})} 
                />
                <span className={
                    !validFlag && (!booking.phone || ![10,11].includes(booking.phone.split('-').join('').split('').length)|| booking.phone.split('-').join('').split('').some(e => !'0123456789'.includes(e)))
                    ? styles.warning
                    : styles.warningHidden
                }>
                    Please enter a valid phone number.
                </span>
                <label className={styles.label} htmlFor="date">Select Date: </label>
                <input
                    className={styles.datetime} 
                    type="date" 
                    name="date"
                    min={minDate}
                    onChange={e => setBooking({...booking, date: e.target.value})} 
                />
                <span className={!validFlag && !booking.date ? styles.warning : styles.warningHidden}>Please select a date for your event.</span>
                <label className={styles.label} htmlFor="time">Select Time: </label>
                <input
                    className={styles.datetime} 
                    type="time"
                    name="time"
                    onChange={e => setBooking({...booking, time: e.target.value})}
                />
                <span className={!validFlag && !booking.time ? styles.warning : styles.warningHidden}>Please select a time for your event.</span>
                <textarea 
                    className={`${styles.textarea} ${styles.textareaBooking}`} 
                    placeholder="Please give a brief description of your event." 
                    onChange={e => setBooking({...booking, description: e.target.value})} 
                />
                <span className={!validFlag && !booking.description ? styles.warning : styles.warningHidden}>Please describe your event.</span>
                <button className={styles.submit} role="submit">Submit</button>
            </form>
        )
    }

    // Message confirmation window, triggered on successful validation and submission
    const confirmWindow = () => {
        return (
            <div className={styles.confirmContainer}>
                <h1 className={`${styles.confirmText} ${styles.confirmThankYou}`}>Thanks for the message!</h1>
                <h3 className={`${styles.confirmText} ${styles.confirmSubThankYou}`}>I'll get back to you ASAP.</h3>
                <button className={styles.confirmOkay} onClick={setConfirm(false)}>Okay</button>
            </div>
        )
    }

    return (
        <div className={styles.container} id="contact">
            <button 
                role="button"
                className={`${styles.toggle} ${styles.toggleContact}`} 
                onClick={() => {
                    setTypeContact("contact")
                    setValidFlag(true)
                }}
            >
                CONTACT
            </button>
            <button 
                role="button"
                className={`${styles.toggle} ${styles.toggleBooking}`} 
                onClick={() => {
                    setTypeContact("booking")
                    setValidFlag(true)
                }}
            >
                BOOKING
            </button>
            <br />
            {typeContact === "contact" && contactWindow()}
            {typeContact === "booking" && bookingWindow()}
            {confirm && confirmWindow()}
        </div>
    )
}

export default ContactAndBooking

try changing line 273 from尝试将第 273 行从

<button className={styles.confirmOkay} onClick={setConfirm(false)}>Okay</button>

to

<button className={styles.confirmOkay} onClick={() => setConfirm(false)}>Okay</button>

then it appears to be working然后它似乎正在工作

When you call setConfirm(false) in your onClick event, what you are actually saying is to run the setConfirm state update as soon as the page loads.当您在 onClick 事件中调用setConfirm(false)时,您实际上是说在页面加载后立即运行 setConfirm state 更新。 What you want to do is create an arrow function in the onClick so that you are passing reference to a function that will be ran once the button is clicked.您要做的是在 onClick 中创建一个箭头 function ,以便您传递对 function 的引用,一旦单击按钮就会运行该引用。

<button className={styles.confirmOkay} onClick={() => setConfirm(false)}>Okay</button>

If you wanted to do more than just call setConfirm, you can create another function and call setConfirm inside of that, then you can just pass the new function as reference so that every time the button is clicked the setConfirm function gets called. If you wanted to do more than just call setConfirm, you can create another function and call setConfirm inside of that, then you can just pass the new function as reference so that every time the button is clicked the setConfirm function gets called.

const handleConfirmUpdate = () => {
   // do some stuff in here if you'd like
   setConfirm(true);
}

<button className={styles.confirmOkay} onClick={handleConfirmUpdate}>Okay</button>

Notice that we are not calling the function, but rather passing a reference.请注意,我们没有调用 function,而是传递了一个引用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM