简体   繁体   English

如何一次有条件地更新多个元素

[英]How to update multiple elements conditionally at once

I'm new to React and trying to figure out what the best way is to update multiple elements at once without having to repeat code all the time.我是 React 的新手,并试图找出最好的方法是一次更新多个元素,而不必一直重复代码。

I got a login page, that has several states: "LOGIN", "SIGNUP" or "FORGOT_PASSWORD".我有一个登录页面,它有几个状态:“LOGIN”、“SIGNUP”或“FORGOT_PASSWORD”。 Depending on the current mode, I am already able to change the used form with renderForm().根据当前模式,我已经能够使用 renderForm() 更改使用的表单。 However, I also need to update some other text in the root component but don't know what the most efficient way is to do so.但是,我还需要更新根组件中的其他一些文本,但不知道最有效的方法是什么。 Of course I could repeat renderForm() for every text snippet I have to change but this seems not very DRY.当然,我可以为我必须更改的每个文本片段重复 renderForm() ,但这似乎不是很干燥。

This is my (very simplified) code:这是我的(非常简化的)代码:

function Login() {
    const [mode, setMode] = useState("LOGIN");

    function renderForm(): ReactElement {
    return (
      <>
        {
          {
            LOGIN: <EmailPasswordForm setMode={setMode} type="login"/>,
            SIGNUP: <EmailPasswordForm setMode={setMode} type="signup"/>,
            FORGOT_PASSWORD: <ForgotPassword setMode={setMode} auth={auth} />,
          }[mode]
        }
      </>
    );
  }


    return (
    <div>
        <h2>
            Sign in to your account //title that needs to change depending on the mode
        </h2>

        {renderForm()}

        <a href="/privacy">Privacy Info</a>
        <p>
            Some text that also needs to change depending on if the mode is "LOGIN", "SIGNUP", or "FORGOT_PASSWORD"
        </p>
        <OAuthSignUpComponents/>
        <p>
            Some  more text that needs to change depending on if the mode is "LOGIN", "SIGNUP", or "FORGOT_PASSWORD"
        </p>
    </div>
    )
}

function EmailPasswordForm({setMode, type}) {

    const handleSubmit = () => {
        type == "login" ? loginLogic() : signupLogic();
    }

    return(
        <form>
            <input type="email/>
            <input type="password"/>
            <button type="button" onClick={handleSubmit}>
            { type == "login" ? <button onClick={setMode("SIGNUP")>Sign up instead</button> : <button onClick={setMode("LOGIN")>Sign in instead</button> }
        </form>
    )
}

function ForgotPasswordForm({setMode}) {
    return(
        <form>
            <input type="email/>
            <button type="button">
        </form>
    )
}

One thing I tried is to use a switch in renderForm() like this:我尝试过的一件事是在 renderForm() 中使用一个开关,如下所示:

const [title, setTitle] = useState("Sign in to your account");

function renderForm(){
    switch(mode) {
        case "LOGIN":
            setTitle("Sign in to your account")
            return <EmailPasswordForm setMode={setMode} type="login"/>;
        case "SIGNUP":
            setTitle("Sign in to your account")
            return <EmailPasswordForm setMode={setMode} type="signup"/>;
        case "FORGOT_PASSWORD":
            setTitle("Reset Password")
            return <ForgotPasswordForm setMode={setMode}/>
    }
}

But that doesn't work either as it results in a too many rerenders error.但这也不起作用,因为它会导致太多的重新渲染错误。

You should have the setTitle in an effect in order for there to be no more rendering issues as you shouldn't have side-effets in your main render function, only in callbacks and effects.您应该在效果中使用 setTitle 以便不再出现渲染问题,因为您的主渲染 function 中不应有副作用,仅在回调和效果中。 You can definitely keep the render form as an object instead of a switch case, as well.您绝对可以将渲染表单保留为 object 而不是开关盒。 Either way would work.无论哪种方式都行得通。

    useEffect(() => {
    switch(mode) {
        case "LOGIN":
            setTitle("Sign in to your account")
        case "SIGNUP":
            setTitle("Sign in to your account")
        case "FORGOT_PASSWORD":
            setTitle("Reset Password")
    }
    return () => {
        // You can then set the original title of the application to clean up once they've logged in.
        // setTitle('Original Title')
    }
}, [mode])

function renderForm(){
    switch(mode) {
        case "LOGIN":
            return <EmailPasswordForm setMode={setMode} type="login"/>;
        case "SIGNUP":
            return <EmailPasswordForm setMode={setMode} type="signup"/>;
        case "FORGOT_PASSWORD":
            return <ForgotPasswordForm setMode={setMode}/>
    }
}

You don't even have to have your switch case or your object in an internal function either.您甚至不必将开关盒或 object 放在内部 function 中。

  const formMap={
    LOGIN: <EmailPasswordForm setMode={setMode} type="login"/>,
    SIGNUP: <EmailPasswordForm setMode={setMode} type="signup"/>,
    FORGOT_PASSWORD: <ForgotPassword setMode={setMode} auth={auth} />,
  };

  return(<div>
    <h2>
        Sign in to your account //title that needs to change depending on the mode
    </h2>

    {formMap[mode]}

    <a href="/privacy">Privacy Info</a>
    <p>
        Some text that also needs to change depending on if the mode is "LOGIN", "SIGNUP", or "FORGOT_PASSWORD"
    </p>
    <OAuthSignUpComponents/>
    <p>
        Some  more text that needs to change depending on if the mode is "LOGIN", "SIGNUP", or "FORGOT_PASSWORD"
    </p>
</div>)

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

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