简体   繁体   中英

How Can I Update A React Component From a Separate Sibling Component in a Separate File?

I am trying to have my navbar update to show the user logged in info after they attempt to login and it is successful. Here's the relevant code files:

App.js

class App extends Component {
  render(){
    return (
      <div>
        <div className="App">
          <header className="App-header">
            <NavBar />
            <Main />
          </header>
        </div>
      </div>
    );
  }
}

export default App;

NavBar.js

const NavBar = () => {
  const [userInfo, SetUserInfo] = useState();

  useEffect(() => {
    SetNavBar(null);
  }, [])

  function SetNavBar(element){
    var user = auth.currentUser;
    console.log(auth.currentUser);

    if (user){
      var userInfo = 
        React.createElement('div', {id : 'userDiv'},
          React.createElement('span', {id : 'userDisplayName'}, user.email),
          React.createElement('span', {id : 'signoutSpan'}, 
            '(', 
            React.createElement('button', {id : 'signoutButton', onClick : (e) => SignOutUser(e.target)}, 'Signout'),
            ')'
          )
        );
      SetUserInfo(userInfo);
    }
    else if(element != null && element.nodeName === 'A'){
      var urlTO = element.href;
        
      if(!urlTO.includes("login") && !urlTO.includes("signup")){
        var userLoginSignupElement = 
          React.createElement('span', {id : 'loginSignupOptions'}, 
            React.createElement(Link, {to : '/login', onClick : (e) => SetNavBar(e.target)}, 'Login'), 
            '/',
            React.createElement(Link, {to : '/signup', onClick : (e) => SetNavBar(e.target)}, 'Signup')
          );
      }
      else{
        var userLoginSignupElement = null;
      }
      SetUserInfo(userLoginSignupElement);
    }
    else{
      var userLoginSignupElement = 
        React.createElement('span', {id : 'loginSignupOptions'}, 
          React.createElement(Link, {to : '/login', onClick : (e) => SetNavBar(e.target)}, 'Login'), 
          '/',
          React.createElement(Link, {to : '/signup', onClick : (e) => SetNavBar(e.target)}, 'Signup')
        );
      SetUserInfo(userLoginSignupElement);
    }
  }

  async function SignOutUser(element){
    try{
      await signOut(auth);
      SetNavBar(null)
    }
    catch(err){
      console.log(err);
    }
  }

  return (
    <div>
      <nav id='navBar'>
        <div id='logoTitleDiv'>
          <img id='navBarLogo' src={logo} alt='Skeeters logo.'></img>
          <Link to='/' onClick={e => SetNavBar(e.target)}>
            <h2 id='pageHeader'>DJSkeeterB</h2>
          </Link>
        </div>
        {userInfo}
      </nav>
    </div>
  );
}

export default NavBar;

Main.js

const Main = () => {
    return (
        <div id='main'>
            <Routes>
                <Route exact path='/' element={<SongRequests/>}/>
                <Route exact path='/upcoming' element={<Upcoming/>}/>
                <Route exact path='/signup' element={<Signup/>}/>
                <Route exact path='/login' element={<Login/>}/>
            </Routes>
        </div>
    );
}

export default Main;

Login.js

const Login = () => {
  const [navigateToHome, SetNavigateToHome] = useState(false);
  const [userEmail, SetUserEmail] = useState('');
  const [userPassword, SetUserPassword] = useState('');

  const userEmailRef = useRef('');
  userEmailRef.current = userEmail;

  const userPasswordRef = useRef('');
  userPasswordRef.current = userPassword;

  const LoginToFirebase = async () => {
    try {
      await signInWithEmailAndPassword(auth, userEmailRef.current, userPasswordRef.current);
      console.log(auth.currentUser);
      document.getElementById('emailInput').innerHTML = '';
      document.getElementById('passwordInput').innerHTML = '';

      SetUserEmail('');
      SetUserPassword('');

      SetNavigateToHome(true);
    } catch (err) {
      console.error(err);
    }
  };

  if(navigateToHome === true){
    return <Navigate to='/'/>;
  }
  return (
      <div id='loginDiv'>
        <div>
          <h2>Login</h2>
        </div>
        <div>
          <label>Email: </label>
          <input id='emailInput' type='email' placeholder='example@gmail.com' onChange={e => SetUserEmail(e.target.value)}/>
        </div>
        <div>
          <label>Password: </label>
          <input id='passwordInput' type='password' placeholder='Password' onChange={e => SetUserPassword(e.target.value)}/>
        </div>
        <button onClick={e => LoginToFirebase()}>Submit</button>
        <div>
          <span id='alreadySignedUpSpan'>
            <Link to='/signup'>Not registered? Signup here</Link>
          </span>
        </div>
      </div>
  );
}

export default Login;

Essentially I have my app show the navbar at all times, and depending on page or user authenticated it updates to be different. The component Main is using react-router-dom to link a few pages currently. After the user signs in or signs up on Login.js or Signup.js they are redirected to the main page. They are successfully logged in using firebase authentication. After the redirect they land on the main page but the navbar isn't updating as I don't know how to call for a state change from what's happening in Login.js to affect NavBar.js .

The navbar has no way of knowing this was a successful authentication it seems. I tried treating auth and auth.currentUser as states to see if when they update they could be used in a useEffect(() => {}, [auth]) way to call the SetNavBar function in NavBar.js .

How can I update my component NavBar , at the end of my function LoginToFirebase() function?

By lifting userEmail state up to your App component (and perhaps all the login functionality) and making your Login component accept a prop of onClickLogin .

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