简体   繁体   中英

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.

I got a login page, that has several states: "LOGIN", "SIGNUP" or "FORGOT_PASSWORD". Depending on the current mode, I am already able to change the used form with 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.

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:

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. You can definitely keep the render form as an object instead of a switch case, as well. 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.

  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>)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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