reactjsreact-hooksconditional-rendering

React: How to use conditional render and react-hooks to update another component's state?


I'm new to React. I'm trying to create a Login/Register Screen. I have three components called Login, Register and SlidingCard. I render these componenets on other jsx file called Screen. In SlidingCard.jsx i have a div and inside this div there are some text and button. When i clicked the button, text and button changes to login related things from register related things. Now the part that i stucked. I mentioned that when i clicked the button on SlidingCard the text changes. But with that click i want to render the Login or Register too. How can i do it?

Login.jsx

import React from "react";
import Input from "./Input";

function Login() {
  return (
    <div className="loginContainer">
      <div className="loginChildContainer">
        <h1>Welcome Back!</h1>
        <p>Lorem lorem lorem lorem lorem</p>
        <Input type="text" placeholder="Username" />
        <Input type="password" placeholder="Password" />
        <button type="submit">Sign In</button>
      </div>
    </div>
  );
}

export default Login;

Register.jsx

import React from "react";
import Input from "./Input";
import FacebookIcon from "@mui/icons-material/Facebook";
import GoogleIcon from "@mui/icons-material/Google";
import TwitterIcon from "@mui/icons-material/Twitter";

function Register() {
  return (
    <div className="registerContainer">
      <h1>Create Account</h1>
      <button>
        <FacebookIcon />
      </button>
      <button>
        <GoogleIcon />
      </button>
      <button>
        <TwitterIcon />
      </button>
      <Input type="text" placeholder="Username" />
      <Input type="text" placeholder="email" />
      <Input type="password" placeholder="Password" />
      <button type="submit">Sign In</button>
    </div>
  );
}

export default Register;

SlidingCard.jsx

import React, { useState } from "react";

function SlidingCard() {
  const [isChanged, setChange] = useState(false);

  const loginPaheseTexts = {
    title: "Hello, Friend!",
    description: "Enter your personal details and start jurney with us.",
    button: "Sign Up"
  };

  const registerPhaseTexts = {
    title: "Welcome Back",
    description:
      "To keep connecting with us please login with your personal info.",
    button: "Sign In"
  };

  const texts = isChanged ? registerPhaseTexts : loginPaheseTexts;

  function handleClick(event) {
    console.log(isChanged);

    setChange(!isChanged);
  }

  return (
    <div>
      <h1>{texts.title}</h1>
      <p>{texts.description}</p>
      <button onClick={handleClick}>{texts.button}</button>
    </div>
  );
}

export default SlidingCard;

Screen.jsx

import React from "react";
import Login from "./Login";
import Register from "./Register";
import SlidingCard from "./SlidingCard";

function Screen(props) {
  return (
    <div className="appContainer">
      {props.isChanged ? <Register /> : <Login />}
      <SlidingCard />
    </div>
  );
}

I checked the interner and i can't find what i'm looking for.


Solution

  • Since your isChanged state is shared between both rendering Login/Register and SlidingCard, you need to "lift" that state up to their common parent, Screen. Once you do that, you can use isChanged directly within Screen, and pass it and setChange down to SlidingCard. This article from the official React docs explains this issue more.

    In the end, you only need to change Screen.jsx and SlidingCard.jsx like so:

    Screen.jsx

    import React from "react";
    import Login from "./Login";
    import Register from "./Register";
    import SlidingCard from "./SlidingCard";
    
    function Screen(props) {
      const [isChanged, setChange] = React.useState(false);
    
      return (
        <div className="appContainer">
          {isChanged ? <Register /> : <Login />}
          <SlidingCard isChanged={isChanged} setChange={setChange} />
        </div>
      );
    }
    
    export default Screen;
    

    SlidingCard.jsx

    import React from "react";
    
    function SlidingCard({isChanged, setChange}) {
    
      const loginPaheseTexts = {
        title: "Hello, Friend!",
        description: "Enter your personal details and start jurney with us.",
        button: "Sign Up"
      };
    
      const registerPhaseTexts = {
        title: "Welcome Back",
        description:
          "To keep connecting with us please login with your personal info.",
        button: "Sign In"
      };
    
      const texts = isChanged ? registerPhaseTexts : loginPaheseTexts;
    
      function handleClick(event) {
        console.log(isChanged);
    
        setChange(!isChanged);
      }
    
      return (
        <div>
          <h1>{texts.title}</h1>
          <p>{texts.description}</p>
          <button onClick={handleClick}>{texts.button}</button>
        </div>
      );
    }
    
    export default SlidingCard;
    

    However, you should also probably consider a more appropriate/readable name for the state, such as showLogin and setShowLogin.