state management for login page, it works but have to click login button twice after putting in user name and pass

huangapple go评论88阅读模式
英文:

state management for login page, it works but have to click login button twice after putting in user name and pass

问题

以下是您要翻译的代码部分:

(App.tsx)

import { useState } from "react";
import "./App.css";
import HomePage from "./pages/home/Home";
import LoginPage from "./pages/login/LoginPage";

function App() {
  const [access, setAccess] = useState(false);

  const onLoginInfo = (onLoginInfo: any) => {
    setAccess(onLoginInfo.access);
    console.log("***<APP>***");
    console.log(onLoginInfo);
    console.log("***</app>***");
  };

  const Greetings = () => {
    if (access) {
      return <HomePage />;
    } else {
      return <LoginPage onLoginInfo={onLoginInfo} />;
    }
  };

  return (
    <div className="App">
      <h1>Welcome to Oylympus!</h1>
      <Greetings />
    </div>
  );
}

export default App;
(LoginPage.tsx)

import React, { useState } from "react";

import classes from "./Login.module.css";

const LoginPage = (props: any) => {
  const [login, setLogin] = useState({
    user: "",
    pass: "",
    access: false,
  });

  const user = "abc";
  const pass = "123";

  const loginSubmitHandler = (event: any) => {
    event.preventDefault();

    if (
      event.currentTarget.username.value === "abc" &&
      event.currentTarget.password.value === "123"
    ) {
      setLogin({
        user: event.currentTarget.username.value,
        pass: event.currentTarget.password.value,
        access: true,
      });
    } else {
      setLogin({
        user: event.currentTarget.username.value,
        pass: event.currentTarget.password.value,
        access: false,
      });
    }

    props.onLoginInfo(login);
    console.log("submit successfull");
  };

  const checkInfoHandler = () => {
    console.log("user: " + login.user);
    console.log("pass: " + login.pass);
    console.log("access: " + login.access);
  };

  return (
    <div className={classes.login}>
      <p>Login Page</p>
      <form onSubmit={loginSubmitHandler}>
        <div>
          <label>
            User:
            <input type="text" name="username" />
          </label>
        </div>
        <div>
          <label>
            Password:
            <input type="password" name="password" />
          </label>
        </div>
        <button className={classes.button}>Login</button>
      </form>
      <div>
        <button
          className={classes.button}
          type="button"
          onClick={checkInfoHandler}
        >
          Check info
        </button>
      </div>
    </div>
  );
};

export default LoginPage;

如果您有任何其他疑问或需要进一步的帮助,请随时提出。

英文:

I capture user/pass info and store it in a useState called login inside Login.tsx and pass it up to App.tsx and then store the access property from login useState to access useState inside the App.tsx

This does work, however, it seems it is one state behind, and have to click the login button twice to go to the next page, which is supposed to be the HomePage.

(App.tsx)

import { useState } from &quot;react&quot;;
import &quot;./App.css&quot;;
import HomePage from &quot;./pages/home/Home&quot;;
import LoginPage from &quot;./pages/login/LoginPage&quot;;

function App() {
  const [access, setAccess] = useState(false);

  const onLoginInfo = (onLoginInfo: any) =&gt; {
    setAccess(onLoginInfo.access);
    console.log(&quot;***&lt;APP&gt;***&quot;);
    console.log(onLoginInfo);
    console.log(&quot;***&lt;/app&gt;***&quot;);
  };

  const Greetings = () =&gt; {
    if (access) {
      return &lt;HomePage /&gt;;
    } else {
      return &lt;LoginPage onLoginInfo={onLoginInfo} /&gt;;
    }
  };

  return (
    &lt;div className=&quot;App&quot;&gt;
      &lt;h1&gt;Welcome to Oylympus!&lt;/h1&gt;
      &lt;Greetings /&gt;
    &lt;/div&gt;
  );
}

export default App;

(LoginPage.tsx)

import React, { useState } from &quot;react&quot;;

import classes from &quot;./Login.module.css&quot;;

const LoginPage = (props: any) =&gt; {
  const [login, setLogin] = useState({
    user: &quot;&quot;,
    pass: &quot;&quot;,
    access: false,
  });

  const user = &quot;abc&quot;;
  const pass = &quot;123&quot;;

  const loginSubmitHandler = (event: any) =&gt; {
    event.preventDefault();

    if (
      event.currentTarget.username.value === &quot;abc&quot; &amp;&amp;
      event.currentTarget.password.value === &quot;123&quot;
    ) {
      setLogin({
        user: event.currentTarget.username.value,
        pass: event.currentTarget.password.value,
        access: true,
      });
    } else {
      setLogin({
        user: event.currentTarget.username.value,
        pass: event.currentTarget.password.value,
        access: false,
      });
    }

    props.onLoginInfo(login);
    console.log(&quot;submit successfull&quot;);
  };

  const checkInfoHandler = () =&gt; {
    console.log(&quot;user: &quot; + login.user);
    console.log(&quot;pass: &quot; + login.pass);
    console.log(&quot;access: &quot; + login.access);
  };

  return (
    &lt;div className={classes.login}&gt;
      &lt;p&gt;Login Page&lt;/p&gt;
      &lt;form onSubmit={loginSubmitHandler}&gt;
        &lt;div&gt;
          &lt;label&gt;
            User:
            &lt;input type=&quot;text&quot; name=&quot;username&quot; /&gt;
          &lt;/label&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;label&gt;
            Password:
            &lt;input type=&quot;password&quot; name=&quot;password&quot; /&gt;
          &lt;/label&gt;
        &lt;/div&gt;
        &lt;button className={classes.button}&gt;Login&lt;/button&gt;
      &lt;/form&gt;
      &lt;div&gt;
        &lt;button
          className={classes.button}
          type=&quot;button&quot;
          onClick={checkInfoHandler}
        &gt;
          Check info
        &lt;/button&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  );
};

export default LoginPage;

I tried writing it a different way but still, the same thing is happening, then I tried to use a useEffect to reload react component but didn't like it.

答案1

得分: 0

调用 setLogin(...) 在 LoginPage 中触发该组件的重新渲染,但是登录变量的值实际上并没有改变——只有在作为重新渲染的一部分重新运行该函数时才会改变。你可以在 State as a Snapshot 文档主题中看到这一点,特别是 State over time 示例,这与你的代码相似:

import { useState } from 'react';

export default function Counter() {
  const [number, setNumber] = useState(0);

  return (
    <>
      <h1>{number}</h1>
      <button onClick={() => {
        setNumber(number + 5);
        alert(number);
      }}>+5</button>
    </>
  )
}

在这里,和你的代码一样,调用 setNumber(...) 来更新状态,但 alert(...) 被调用时仍然使用当前状态的值,这个值仍然是 0。状态直到回调完成之后才会被更新,即使在回调完成后,它也会通过重新渲染组件来实现(number 变量在单个函数执行中永远不会改变;如果需要重新渲染,函数将重新运行,并且 useState(0) 将返回新值 5 给新的 number 变量)。

同样,当你调用 props.onLoginInfo(login) 时,它仍然传递登录状态的“旧”值,因为这是当前渲染中该变量的值。


有几种方法可以使这个工作。首先要问的是 LoginPage 是否需要保持状态。该组件实际上并没有使用它(除了 checkInfoHandler,看起来可能只是用于调试,但即使那个也不一定需要使用状态),而 App 组件负责维护该状态以确定是渲染 LoginPage 还是 HomePage 组件。在这种情况下,你可以消除 LoginPage 中的所有状态管理,只需调用 props.onLoginInfo(...) 回调并传递新值:

const loginSubmitHandler = (event: any) => {
  event.preventDefault();

  if (
    event.currentTarget.username.value === "abc" &&
    event.currentTarget.password.value === "123"
  ) {
    props.onLoginInfo({
      user: event.currentTarget.username.value,
      pass: event.currentTarget.password.value,
      access: true,
    });
  } else {
    props.onLoginInfo({
      user: event.currentTarget.username.value,
      pass: event.currentTarget.password.value,
      access: false,
    });
  }

  console.log("submit successfull");
};

如果 LoginPage 需要状态,那么你可以保留 setLogin(...) 状态调用,但确保使用相同的值调用 props.onLoginInfo(...)。还有其他方法,但它们稍微复杂一些。

const loginSubmitHandler = (event: any) => {
  event.preventDefault();

  const isLoginSuccessful =
    event.currentTarget.username.value === "abc" &&
    event.currentTarget.password.value === "123";

  const newLogin = {
    user: event.currentTarget.username.value,
    pass: event.currentTarget.password.value,
    access: isLoginSuccessful,
  };

  setLogin(newLogin);
  props.onLoginInfo(newLogin);
  console.log("submit successfull");
};
英文:

Calling setLogin(...) in the LoginPage triggers a re-render of that component, but the value of the login variable doesn't actually change—that only changes when the function is re-run as part of the re-render. You can see this in the State as a Snapshot documentation topic, specifically the State over time sample, which is similar to your code:

import { useState } from &#39;react&#39;;

export default function Counter() {
  const [number, setNumber] = useState(0);

  return (
    &lt;&gt;
      &lt;h1&gt;{number}&lt;/h1&gt;
      &lt;button onClick={() =&gt; {
        setNumber(number + 5);
        alert(number);
      }}&gt;+5&lt;/button&gt;
    &lt;/&gt;
  )
}

Here, like your code, the setNumber(...) is called to update the state, but alert(...) is called with the value of the current state, which is still 0. The state will not be updated until after the callback finishes, and even then it will do so by re-rendering the component (the number variable will never change within a single function execution; if a re-render is required, the function will re-run and useState(0) will return the new value, 5, to the new number variable).

Similarly, when you call props.onLoginInfo(login), it is still passing in the "old" value of the login state, because that is the value of that variable within the current render.


There are a couple of ways I can see to make this work. First is to ask whether LoginPage even needs to keep state. Nothing in that component actually uses it (aside from checkInfoHandler, which looks like it might just be for debugging, but even that doesn't necessarily need to use state), and the App component is the one responsible for maintaining that state for the purposes of determining whether to render the LoginPage or the HomePage component. In that case you could eliminate all of the state management from LoginPage and just call the props.onLoginInfo(...) callback with the new value:

const loginSubmitHandler = (event: any) =&gt; {
event.preventDefault();
if (
event.currentTarget.username.value === &quot;abc&quot; &amp;&amp;
event.currentTarget.password.value === &quot;123&quot;
) {
props.onLoginInfo({
user: event.currentTarget.username.value,
pass: event.currentTarget.password.value,
access: true,
});
} else {
props.onLoginInfo({
user: event.currentTarget.username.value,
pass: event.currentTarget.password.value,
access: false,
});
}
console.log(&quot;submit successfull&quot;);
};

If LoginPage does need state for something, then you could keep the setLogin(...) state calls but just make sure to call props.onLoginInfo(...) with the same value. There are other ways, too, but they are a little more advanced.

const loginSubmitHandler = (event: any) =&gt; {
  event.preventDefault();

  const isLoginSuccessful =
    event.currentTarget.username.value === &quot;abc&quot; &amp;&amp;
    event.currentTarget.password.value === &quot;123&quot;;

  const newLogin = {
    user: event.currentTarget.username.value,
    pass: event.currentTarget.password.value,
    access: isLoginSuccessful,
  };

  setLogin(newLogin);
  props.onLoginInfo(newLogin);
  console.log(&quot;submit successfull&quot;);
};

答案2

得分: 0

以下是您要翻译的代码部分:

import * as React from 'react';
import { useState } from 'react';

const USER_NAME = 'abc';
const USER_PASSWORD = '123';

const LoginPage = ({ onLoginInfo }) => {
  const [login, setLogin] = useState({
    user: '',
    pass: '',
    access: false,
  });

  const loginSubmitHandler = (event) => {
    event.preventDefault();
    const user = event.currentTarget.username.value;
    const pass = event.currentTarget.password.value;
    const access = user === USER_NAME && pass === USER_PASSWORD ? true : false;
    const _login = { user, pass, access };
    setLogin(_login);
    onLoginInfo(_login); //go home page
  };

  const checkInfoHandler = () => {
    console.log('submit successfull');

    console.log('user: ' + login.user);
    console.log('pass: ' + login.pass);
    console.log('access: ' + login.access);
  };

  return (
    <div>
      <p>Login Page</p>
      <form onSubmit={loginSubmitHandler}>
        <div>
          <label>
            User:
            <input type="text" name="username" />
          </label>
        </div>
        <div>
          <label>
            Password:
            <input type="password" name="password" />
          </label>
        </div>
        <button>Login</button>
      </form>
      <div>
        <button type="button" onClick={checkInfoHandler}>
          Check info
        </button>
      </div>
    </div>
  );
};

export default LoginPage;

请注意,我已经保留了原始代码的格式和结构,只是将其中的文本部分翻译成中文。

英文:

You can try this:

import * as React from &#39;react&#39;;
import { useState } from &#39;react&#39;;
const USER_NAME = &#39;abc&#39;;
const USER_PASSWORD = &#39;123&#39;;
const LoginPage = ({ onLoginInfo }) =&gt; {
const [login, setLogin] = useState({
user: &#39;&#39;,
pass: &#39;&#39;,
access: false,
});
const loginSubmitHandler = (event: any) =&gt; {
event.preventDefault();
const user = event.currentTarget.username.value;
const pass = event.currentTarget.password.value;
const access = user === USER_NAME &amp;&amp; pass === USER_PASSWORD ? true : false;
const _login = { user, pass, access };
setLogin(_login);
onLoginInfo(_login); //go home page
};
const checkInfoHandler = () =&gt; {
console.log(&#39;submit successfull&#39;);
console.log(&#39;user: &#39; + login.user);
console.log(&#39;pass: &#39; + login.pass);
console.log(&#39;access: &#39; + login.access);
};
return (
&lt;div&gt;
&lt;p&gt;Login Page&lt;/p&gt;
&lt;form onSubmit={loginSubmitHandler}&gt;
&lt;div&gt;
&lt;label&gt;
User:
&lt;input type=&quot;text&quot; name=&quot;username&quot; /&gt;
&lt;/label&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;label&gt;
Password:
&lt;input type=&quot;password&quot; name=&quot;password&quot; /&gt;
&lt;/label&gt;
&lt;/div&gt;
&lt;button&gt;Login&lt;/button&gt;
&lt;/form&gt;
&lt;div&gt;
&lt;button type=&quot;button&quot; onClick={checkInfoHandler}&gt;
Check info
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
);
};
export default LoginPage;

huangapple
  • 本文由 发表于 2023年2月14日 21:56:46
  • 转载请务必保留本文链接:https://go.coder-hub.com/75448869.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定