Search code examples
javascriptreactjsexpressaxiospassport.js

How can I pass in props from App.js to my login component?


I'm new to React. I'm having trouble with getting React to recognize a prop passed in from App.js to the Login component. Specifically what I'm trying to do is getting React to do two things: 1. To check if a user is logged in. 2. What user is currently logged in. I'm using Passport, passport-local, Mongoose, MongoDB, Axios, Express, and react-router-dom to make this happen. When I attempt to log in a user I created in the database I get the following in the console:

TypeError: "this.props.updateUser is not a function"
    onSubmit login.component.js:42

App.js:

import React, { Component } from "react";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
import "bootstrap/dist/css/bootstrap.min.css";
import axios from "axios";

/* Begin Import Components */
import NavigationBar from "./components/navbar.component";

import MainLanding from "./components/main-landing.component";
import Contact from "./components/general-components/contact.component";
import Register from "./components/general-components/register.component";
import Login from "./components/general-components/login.component";
import ProductsList from "./components/product-components/products-list.component";
import ProductDetails from "./components/product-components/product-details.component";
import ProductCreate from "./components/product-components/product-create.component";
import ProductEdit from "./components/product-components/product-edit.component";
import ProductDelete from "./components/product-components/product-delete.component";
import UsersList from "./components/user-components/users-list.component";
import UserDetails from "./components/user-components/user-details.component";
import OrdersList from "./components/order-components/orders-list.component";
import OrderDetails from "./components/order-components/order-details.component";
import OrderCreate from "./components/order-components/order-create.component";
import OrderEdit from "./components/order-components/order-edit.component";
/* End Import Components */

class App extends Component {

  constructor(props) {
    super(props);

    this.state = {
        loggedIn: false,
        user: {}
    }

    this.getUser = this.getUser.bind(this);
    this.componentDidMount = this.componentDidMount.bind(this);
    this.updateUser = this.updateUser.bind(this)
  }

  getUser() {
    axios.get('http://localhost:4000/logged_in').then(response => {
      console.log('Get user response: ')
      console.log(response.data)
      if (response.data.user) {
        this.setState({
          loggedIn: true,
          user: response.data.user
        })
      } else {
        console.log('Get user: no user');
        this.setState({
          loggedIn: false,
          user: {}
        })
      }
    })
  }

  componentDidMount() {
    this.getUser();
  }

  updateUser(userObject) {
    this.setState(userObject)
  }

  render() {
    return (
      <Router>
        <NavigationBar />
        <div className="container">
          {/* Begin Routes. Begin General Routes */}
          <Route path="/" exact component={MainLanding} />
          <Route path="/contact" exact component={Contact} />
          <Route path="/register" exact component={Register} />
          <Route path='/login' render={(props) => <Login {...props} />}/>
          {/* End General Routes. Begin Products Routes */}
          <Switch>
            <Route path="/products/" exact component={ProductsList} />
            <Route path="/products/new" exact component={ProductCreate} />
            <Route path="/products/:id" exact component={ProductDetails} />
            <Route path="/products/:id/edit" exact component={ProductEdit} />
            <Route path="/products/:id/delete" exact component={ProductDelete} />
          </Switch>
          {/* End Products Routes. Begin Users Routes */}
          <Switch>
            <Route path="/users/" exact component={UsersList} />
            <Route path="/users/:id" exact component={UserDetails} />
          </Switch>
          {/* End Users Routes. Begin Orders Routes */}
          <Switch>
            <Route path="/orders/" exact component={OrdersList} />
            <Route path="/orders/new" exact component={OrderCreate} />
            <Route path="/orders/:id" exact component={OrderDetails} />
            <Route path="/orders/:id/edit" exact component={OrderEdit} />
          </Switch>
          {/* End Orders Routes. End Routes */}
        </div>
      </Router>
    );
  }
}

export default App;

Login Component:

import React, { Component } from "react";
import { Col, Form, Button } from "react-bootstrap";
import axios from "axios";

class Login extends Component {

    constructor(props) {
        super(props);

        this.state = {
            username: "",
            password: ""
        }

        this.onChangeUsername = this.onChangeUsername.bind(this);
        this.onchangePassword = this.onchangePassword.bind(this);
        this.onSubmit = this.onSubmit.bind(this);
    }

    onChangeUsername(e) {
        this.setState({
            username: e.target.value
        });
    }

    onchangePassword(e) {
        this.setState({
            password: e.target.value
        });
    }

    onSubmit(e) {
        e.preventDefault();

        axios.post("http://localhost:4000/login", {
            username: this.state.username,
            password: this.state.password
        }).then(res => {
                console.log(res)
                if (res.status === 200) {
                    this.props.updateUser({
                        loggedIn: true,
                        username: res.data.username
                    })
                }
            }).catch(error => {
                console.log(error);
            });

        this.setState({
            username: "",
            password: ""
        })
        this.props.history.push("/");
    }

    render() {
        return (
            <div className="text-center">
                <h2>Login</h2>
                <Form onSubmit={this.onSubmit}>
                    <Form.Row>
                        <Form.Group as={Col} sm={{ span: 6 }}>
                            <Form.Label htmlFor="formUsername">Username</Form.Label>
                            <Form.Control
                                        controlid="formUsername"
                                        type="text"
                                        value={this.state.username}
                                        onChange={this.onChangeUsername}
                                        placeholder="Enter username"
                                        />
                        </Form.Group>
                        <Form.Group as={Col} sm={{ span: 6 }}>
                            <Form.Label htmlFor="formPassword">Password</Form.Label>
                            <Form.Control
                                        controlid="formPassword"
                                        type="password"
                                        value={this.state.password}
                                        onChange={this.onchangePassword}
                                        placeholder="Enter password"
                                        />
                        </Form.Group>
                    </Form.Row>
                    <Button variant="success" type="submit">
                        Login
                    </Button>
                </Form>
            </div>
        )
    }
}

export default Login;

Let me know if I need to provide any additional information. Thank you.


Solution

  • The function updateUser() is defined correctly but you need to pass it to the Login component:

    App.js

    <Route path='/login' render={(props) =>
      <Login {...props} updateUser={this.updateUser} />
    }/>
    

    This will append props.updateUser to the Login component on top of all the props from the parent component (App.js).