簡體   English   中英

反應無法識別第一次渲染時輸入框更改的 state

[英]React not recognizing changed state from input boxes on first render

各位開發者好

我正在 React 中構建一個基本客戶端來測試我的 API 的一些功能,誠然,我的 Node.js 知識遠遠超過了我對反應、狀態和鈎子的理解。

問題:我有 3 個輸入字段,一個用於“用戶名”,一個用於“密碼”,一個用於“確認密碼”。 這些輸入值中的每一個都基於“訂閱者” useState 掛鈎進行更新。 我使用 handleChange function 設置,每個輸入中都有一個 onChange 偵聽器。

然后,我有兩個按鈕,它們依賴於單獨使用 state 掛鈎,稱為 logOrReg 以根據用戶是否要登錄或注冊進行更改。 這個鈎子將調整function 提交按鈕的點擊以及提交按鈕中的文本和用於切換登錄或注冊的按鈕中的文本。

在我啟動應用程序的第一次渲染中,logOrReg state 似乎設置正確,即提交按鈕 function: function 已登錄或注冊按鈕“已登錄或注冊”按鈕和提交按鈕文本:“注冊”。

當我開始在輸入中輸入文本時,它們會相應更新,訂閱者 state 通過放置在每個輸入中的 handleChange function 也會相應更新。 I then go to click the submit button, it then hits the postSub function but the the subscribers state does not get passed to the function and so the API receives blank values in its console and the subscriber.username and subscriber.password targets in the postSub function 在客戶端的 console.log 中顯示為空白。

但是,如果我點擊“已經有一個帳戶?” 按鈕切換(輸入中的文本保持不變),然后單擊“沒有帳戶?” 按鈕按預期更改回寄存器 state。 然后我單擊“注冊”,輸入中設置的訂閱者 state 的值突然傳遞到 postSub function 和 API 接收新用戶名和用戶名並注冊。

Then if I try to update the values in the input fields again the updated values don't get passed to the postSub function but instead the values from the initial registration get passed to the function and subsequently the api returning a message on my API console stating用戶已經注冊。

當在谷歌開發者控制台中查看我的組件和狀態時,它們似乎都在正確更新,所以當我點擊提交時,輸入的 state 沒有傳遞給 function,這非常令人困惑。 我的假設是我不了解 useState 掛鈎是如何工作的,但如果它們在開發工具中正確顯示,我不知道如何理解為什么沒有將這些值傳遞給 function。

我真的希望這是有道理的,描述它是如此奇怪的問題。

編碼:

import React, {useState, useEffect} from 'react'
import Pusher from 'pusher-js';
import axios from "axios";
import Table from '@mui/material/Table';
import TableHead from '@mui/material/TableHead';
import TableCell from '@mui/material/TableCell';
import TableRow from '@mui/material/TableRow';

const PUSHER_APP_KEY = "b4173b2b1b29274b8621";
const PUSHER_APP_CLUSTER = "eu";

function Resthome(e) {

    const pusher = new Pusher(PUSHER_APP_KEY, {cluster: PUSHER_APP_CLUSTER})

    // var [activeOrders,     setActiveOrders] = useState([])
    // axios.get("hhttp://localhost:3000/restaurants/getactiveorders")
    // .then(response => {         setActiveOrders(response)     })
    // console.log(activeOrders) This will be called when your component is mounted
    useEffect(() => {

        

        const channel = pusher.subscribe("rests")
        let mounted = true;
        if (mounted) {
            console.log("mounted")

            channel.bind("inserted", (data) => {
                console.log("inserted")
                console.log("data", JSON.stringify(data))

                alert("you have been subscribed")

            })
        }
        return (() => {
            pusher.unsubscribe("rests")
            mounted = false
        })
    }, []);

    // [] would ensure that useEffect is executed only once

    function LoginOrRegister() {

         const [subscriber,
            setSubscriber] = useState({
                username: "",
                password: "",
                confirmPassword: ""
            })

               const [logOrReg,
            setLogOrReg] = useState({type: "reg", function: postSub, submitButton: "register", switchButton: "already have an account?"})
       

        function handleChange(event) {

            const newValue = event.target.value;
            const inputName = event.target.name;

            setSubscriber(prevValue => {
                if (inputName === "username") {
                    return {username: newValue, password: prevValue.password, confirmPassword: prevValue.confirmPassword}
                } else if (inputName === "password") {
                    return {username: prevValue.username, password: newValue, confirmPassword: prevValue.confirmPassword}
                } else if (inputName === "confirmPassword") {
                    return {username: prevValue.username, password: prevValue.password, confirmPassword: newValue}
                }
            })

            console.log("set sub username", subscriber.username, "set sub password", subscriber.password)

        }

        function Switch(e) {

            e.preventDefault()

            if (logOrReg.type === "reg") {
                setLogOrReg({type: "log", function: logUser, submitButton: "login", switchButton: "Dont have an account?"})
            } else if (logOrReg.type === "log") {
                setLogOrReg({type: "reg", function: postSub, submitButton: "register", switchButton: "Already have an account?"})
            }

        }

        async function postSub(e) {
            e.preventDefault()

            console.log("password", subscriber.password, "username", subscriber.username)

            try {
                if (subscriber.password === subscriber.confirmPassword) {
                    await axios
                        .post("http://localhost:3000/restaurants/register", {

                        username: subscriber.username,
                        password: subscriber.password

                    })
                        .then(response => {
                            if (response.status === 201) {
                                console.log("request sent successfully")
                            }
                        })

                } else {
                    alert("Passwords dont match")
                }
            } catch (err) {
                console.log(err)
            }
        }

        async function logUser(e) {
            e.preventDefault()

            try {
                if (subscriber.password === subscriber.confirmPassword) {
                    await axios
                        .post("http://localhost:3000/restaurants/login", {

                        username: subscriber.username,
                        password: subscriber.password

                    })
                        .then(response => {
                            if (response.status === 201) {
                                console.log("request sent successfully")
                                console.log(response)
                            }
                        })

                } else {
                    alert("Passwords dont match")
                }
            } catch (err) {
                console.log(err)
            }
        }

        // var [logOrReg,     setlogOrReg] = useState({username: "", password: "",
        // confirmPassword: ""})

     

        return (
            <div>
                <form onSubmit={logOrReg.function}>
                    <h1>Signup</h1>
                    <input
                        name="username"
                        onChange={handleChange}
                        placeholder="username"
                        value={subscriber.username}
                        label="email"></input>
                    <input
                        name="password"
                        onChange={handleChange}
                        placeholder="password"
                        value={subscriber.password}
                        label="password"></input>
                    <input
                        name="confirmPassword"
                        onChange={handleChange}
                        placeholder="confirmPassword"
                        value={subscriber.confirmPassword}
                        label="password"></input>
                    <button type="submit">
                        <h3>
                            {logOrReg.submitButton}
                        </h3>
                    </button>
                </form>
                <button name="login-or-register" onClick={Switch}>
                    <h3>{logOrReg.switchButton}</h3>
                </button>
            </div>

        )
    };

    return (
        <div>
            <LoginOrRegister/>
            <Table>
                <TableHead>
                    <TableRow>
                        <TableCell>ID</TableCell>
                        <TableCell align="right">Total</TableCell>
                        <TableCell align="right">Item names</TableCell>
                        <TableCell align="right">Status</TableCell>
                        <TableCell align="right">Time Placed</TableCell>
                    </TableRow>
                </TableHead>
            </Table>
        </div>
    )
}

export default Resthome

原因

這里的問題是您的函數沒有參考您在反應文檔中描述的狀態

解釋

如果您將函數存儲在狀態中,則該函數從外部范圍捕獲變量(AFAIK 復制操作)。

當您的狀態發生變化時,您的函數仍然保留舊副本。 如果您希望您的函數捕獲新狀態,則必須調用它(在您的狀態中創建對該函數的新引用)。

當您的狀態發生變化時,您可以使用“useEffect”重新呈現您的調用函數

可能的解決方案

StackBlitz 上的示例

但...

最后你應該更喜歡從你的狀態中提取你的函數,並在一個靜態函數中做出決定

對於任何這可能有助於查看我的解決方案的人。 我還清理了鳥巢並將 LoginOrRegister 組件移動到它自己的文件中。

import React, {useState} from 'react'
import axios from "axios";

const MODE_REGISTER = "register";
const MODE_LOGIN = "login";

function LoginOrRegister({setCount, count}) {

    // REGISTER FUNCTION
    async function register() {

        console.log("password", formState.password, "username", formState.username)

        if (formState.password === formState.confirmPassword) {
            axios({
                method: "POST",
                data: {
                    username: formState.username,
                    password: formState.password
                },
                withCredentials: true,
                url: "http://localhost:3000/restaurants/register"
            }).then((res) => {console.log(res)
            
            setCount("allow")
            });

        } else {

            alert("passwords dont match")
        }

    };

    // LOGIN FUNCTION
    async function login() {

        console.log("password", formState.password, "username", formState.username)

        if (formState.password === formState.confirmPassword) {
            axios({
                method: "POST",
                data: {
                    username: formState.username,
                    password: formState.password
                },
                withCredentials: true,
                url: "http://localhost:3000/restaurants/login"
            }).then((res) => {
                
        console.log(res)
    setCount("allow")
    });

        } else {

            alert("passwords dont match")
        }

    };

    const [formState,
        setFormState] = useState({mode: MODE_REGISTER, username: "", password: "", confirmPassword: "", logState: "false"});

    function handleChange(event) {
        const newValue = event.target.value;
        const inputName = event.target.name;

        setFormState({
            ...formState,
            [inputName]: newValue
        })
    };

    function handleSubmit(event) {
        event.preventDefault();

        switch (formState.mode) {
            case MODE_LOGIN:
                login()
                // code block
                break;
            case MODE_REGISTER:
                register()
                // code block
                break;
            default:
                register() // defaulted to register
                // code block
        }
        console.log("from state", formState);
    };

    function switchMode() {
        setFormState({
            ...formState,
            mode: formState.mode === MODE_REGISTER
                ? MODE_LOGIN
                : MODE_REGISTER
        })

    };

    

    return (
        <div state={formState.logState}>
            <form onSubmit={handleSubmit}>
                <h1>Signup</h1>
                <input
                    name="username"
                    onChange={handleChange}
                    placeholder="username"
                    value={formState.username}
                    label="email"></input>
                <input
                    name="password"
                    onChange={handleChange}
                    placeholder="password"
                    value={formState.password}
                    label="password"></input>
                <input
                    name="confirmPassword"
                    onChange={handleChange}
                    placeholder="confirmPassword"
                    value={formState.confirmPassword}
                    label="password"></input>
                <button type="submit">
                    <h3>
                        {formState.mode}
                    </h3>
                </button>
            </form>
            <button name="login-or-register" onClick={switchMode}>
                <h3>Switch to {formState.mode === MODE_REGISTER
                        ? MODE_LOGIN
                        : MODE_REGISTER}</h3>
            </button>
        </div>

    )
};

export default LoginOrRegister

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM