0

The situation is as follows: I have a Navigation, and Login components. Login is only an exported function, which logs the user in. It's this:

export function login() {
    var email = document.getElementById('email').value;
    var password = document.getElementById('password').value;
    firebase
        .auth()
        .signInWithEmailAndPassword(email, password)
        .then(() => {
                document.getElementById('close').click();
                document.getElementById('questions').click();
            }
        ).catch(e => console.log(e));
}

This works almost perfectly.

This is my Navigation component

render() {
    return (
        <BrowserRouter>
            <React.Fragment>
                <Navbar>
                    <Navbar.Header>
                        <Navbar.Brand>
                            <Link id='home' to="/">UczIchApp</Link>
                        </Navbar.Brand>
                    </Navbar.Header>
                    <Nav>
                        <LinkContainer id='about' to='/about'>
                            <NavItem>O nas</NavItem>
                        </LinkContainer>
                        {// The issue starts here
                            this.state.user ?
                                <React.Fragment>
                                    <LinkContainer id="questions" to='/questions'>
                                        <NavItem>Zadania</NavItem>
                                    </LinkContainer>
                                    <NavItem onClick={logout.bind(this)}>Wyloguj się</NavItem>
                                </React.Fragment>
                                :
                                <NavItem onClick={this.openLogin}>Zaloguj się</NavItem>
                        }
                    </Nav>
                </Navbar>
                <Switch>
                    <Route exact path="/about" component={AboutComponent}/>
                    <Route exact path="/questions" component={QuestionsComponent}/>
                    <Route exact path="/" component={HomeComponent}/>
                    <Route path='/question/:id' component={QuestionComponent}/>
                </Switch>
                <ModalComponent show={this.state.show} changeShowState={this.changeShowState}/>
            </React.Fragment>
        </BrowserRouter>
    )
}

So when I log the user in, I want him to be transferred to the Questions route. I'm trying to do it with click. But the problem is, the Questions link is not rendered yet, so I'm getting the: TypeError: "document.getElementById(...) is null" error.

How can I make it wait until the component is rendered?

Alex Ironside
  • 4,658
  • 11
  • 59
  • 119
  • Why do you access the DOM nodes in your logic function? Please checkout [my answer](https://stackoverflow.com/a/50738496/4312466), how to do it in the React way. – Jordan Enev Jun 07 '18 at 10:19

3 Answers3

1

You can redirect a user programmatically. There are a few ways to do that, for instance:

If your Login component extends React.Component you have an access to history object like:

class Login extends React.Component {
   // use `this.props.history.push('/some/path')` here
};

So you can pass this.props.history to your login function and call push when you're logged in:

export function login(history) {
    var email = document.getElementById('email').value;
    var password = document.getElementById('password').value;
    firebase
        .auth()
        .signInWithEmailAndPassword(email, password)
        .then(() => {
                history.push('/questions');
            }
        ).catch(e => console.log(e));
}
klimat
  • 24,711
  • 7
  • 63
  • 70
  • I'm a little lost. How do I initiate the history object? – Alex Ironside Jun 07 '18 at 10:15
  • You don't have to if you have `extend React.Component`. Just use it as it is. This is works like this since React Router v4, ensure you have it. Read link I provided as well https://stackoverflow.com/questions/31079081/programmatically-navigate-using-react-router because there are other options to make redirect from code, one of them for sure will work for you. – klimat Jun 07 '18 at 10:17
0

It's a really bad idea to access the DOM nodes in the way you're doing it.

The (React) flow you should follow, has to be:

  1. The user enters his credentials (let's say you have LoginForm component).
  2. Submits the form.
  3. On submit, you have a callback that will call your login function and pass the credentials as parameters (without coupling the login function with the DOM nodes).
  4. If everything is fine redirect the user to the desired route, using the react-router API. Something like login(credentials).then(() => history.push('/questions')). Here you can read more about how to programmatically do the redirect.

Pseudo code:

import React from "react";
import { withRouter } from "react-router-dom"

class LoginForm extends React.Component {
   constructor (super) {
     this.state = {
       email: null,
       password: null
     }

     this.login = this.login.bind(this)
   }


  login() {
    const { email, password } = this.state

    firebase
      .auth()
      .signInWithEmailAndPassword(email, password)
      .then(() => this.props.history.push('/questions'))
      .catch(e => console.log(e))
  }

   render() {
     <form onSubmit={this.login}>
      // Controlled inputs
      <input name='email' />
      <input name='password' />

      <input type='submit' value='Submit' />
     </form>
   }
}

// Please checkout: https://stackoverflow.com/a/42716055/4312466
export default withRouter(LoginForm)

I'll recommend you to take a closer look to the Thinking in React official documentation.

Jordan Enev
  • 16,904
  • 3
  • 42
  • 67
0

Where are you setting "user" property in state? Maybe try to use there "history.push" from react-router if user is logged.

Koli96
  • 69
  • 1
  • 8