简体   繁体   中英

How to pass data between 2 classes in ReactJS

I am having an issue with what I believe is react hooks for a school assignment.

In my app.js, I am using conditional rendering to render 2 different navbar's: 1 for a normal user and 1 for an admin. I am having trouble understanding how to change the app.js state where I render the navbar, from the login.js. Below is my code.

Login.js

  handleLogon(){
    try{
      if(this.username == "user1" && this.password == "pass123"){
        //send info to app.js
      }
    }
    catch{
      this.setState({
        message: "Incorrect Credentials"
      });
    }
  }

App.js

  //create state for loggedin 
  constructor(props) {
    super(props);

    this.state = {
      isLoggedIn: false
    }
  }

  handleLogonChange(b) {
    if(b) {
      this.setState({
        isLoggedIn: true
      });
    }
  }

App.js rendering

render() {
    if (this.state.isLoggedIn) {
      return (
        <div>
          <nav className="navbar navbar-expand navbar-dark bg-dark">
            <a href="/menus" className="navbar-brand">
              Blue Devil Cafe Online
          </a>
            <div className="navbar-nav mr-auto">
              <li className="nav-item">
                <Link to={"/menus"} className="nav-link">
                  Menus
              </Link>
              </li>
              <li className="nav-item">
                <Link to={"/addmenu"} className="nav-link">
                  Add Menu
              </Link>
              </li>
              <li className="nav-item">
                <Link to={"/menuitems"} className="nav-link">
                  Menu Items
              </Link>
              </li>
              <li className="nav-item">
                <Link to={"/addmenuitem"} className="nav-link">
                  Add Menu Item
              </Link>
              </li>
            </div>
          </nav>

          <div className="container mt-3">
            <Switch>
              <Route exact path={["/", "/menuitems"]} component={MenuItemList} />
              <Route exact path="/addmenuitem" component={AddMenuItem} />
              <Route path="/menuitems/:id" component={MenuItem} />

              <Route exact path={"/menus"} component={MenuList} />
              <Route exact path="/addmenu" component={AddMenu} />
              <Route path="/menus/:id" component={Menu} />
            </Switch>
          </div>

        </div>
      )
    }
    else {
      return (
        <div>
          <nav className="navbar navbar-expand navbar-dark bg-dark">
            <a href="/menus" className="navbar-brand">
              Blue Devil Cafe Online
          </a>
            <div className="navbar-nav mr-auto">
              <li className="nav-item">
                <Link to={"/home"} className="nav-link">
                  Home
              </Link>
              </li>
              <li className="nav-item">
                <Link to={"/calendar"} className="nav-link">
                  Calendar
              </Link>
              </li>
              <li className="nav-item">
                <Link to={"/cart"} className="nav-link">
                  Cart
              </Link>
              </li>
              <li className="nav-item">
                <Link to={"/login"} className="nav-link">
                  Login
              </Link>
              </li>
            </div>
          </nav>

          <div className="container mt-3">
            <Switch>
              <Route exact path={"/home"} component={Home} />
              <Route exact path={"/calendar"} component={Calendar} />
              <Route exact path={"/cart"} component={Cart} />
              <Route exact path={"/login"} component={Login} />
            </Switch>
          </div>

        </div>
      )
    }
  }

What I want to send from login is a true boolean to the app so that it can render the change the condition to render the admin's navbar isntead of the general user's navbar. If there is anything else you need please let know.

Try using the render method instead of component on the Route. In that way, you can pass the function as a prop reference to Login and get value from child to update the parent.

Here is the code:

//create state for loggedin 
 constructor(props) {
  super(props);

  this.state = {
    isLoggedIn: false
  }
}

handleLogonChange(b) 
{
  if(b) {
    this.setState({
      isLoggedIn: true
    });
  }
}

render() {
  if (this.state.isLoggedIn) {
    return (
      <div>
        <nav className="navbar navbar-expand navbar-dark bg-dark">
          <a href="/menus" className="navbar-brand">
            Blue Devil Cafe Online
        </a>
          <div className="navbar-nav mr-auto">
            <li className="nav-item">
              <Link to={"/menus"} className="nav-link">
                Menus
            </Link>
            </li>
            <li className="nav-item">
              <Link to={"/addmenu"} className="nav-link">
                Add Menu
            </Link>
            </li>
            <li className="nav-item">
              <Link to={"/menuitems"} className="nav-link">
                Menu Items
            </Link>
            </li>
            <li className="nav-item">
              <Link to={"/addmenuitem"} className="nav-link">
                Add Menu Item
            </Link>
            </li>
          </div>
        </nav>

        <div className="container mt-3">
          <Switch>
            <Route exact path={["/", "/menuitems"]} component={MenuItemList} />
            <Route exact path="/addmenuitem" component={AddMenuItem} />
            <Route path="/menuitems/:id" component={MenuItem} />

            <Route exact path={"/menus"} component={MenuList} />
            <Route exact path="/addmenu" component={AddMenu} />
            <Route path="/menus/:id" component={Menu} />
          </Switch>
        </div>

      </div>
    )
  }
  else {
    return (
      <div>
        <nav className="navbar navbar-expand navbar-dark bg-dark">
          <a href="/menus" className="navbar-brand">
            Blue Devil Cafe Online
        </a>
          <div className="navbar-nav mr-auto">
            <li className="nav-item">
              <Link to={"/home"} className="nav-link">
                Home
            </Link>
            </li>
            <li className="nav-item">
              <Link to={"/calendar"} className="nav-link">
                Calendar
            </Link>
            </li>
            <li className="nav-item">
              <Link to={"/cart"} className="nav-link">
                Cart
            </Link>
            </li>
            <li className="nav-item">
              <Link to={"/login"} className="nav-link">
                Login
            </Link>
            </li>
          </div>
        </nav>

        <div className="container mt-3">
          <Switch>
            <Route exact path={"/home"} component={Home} />
            <Route exact path={"/calendar"} component={Calendar} />
            <Route exact path={"/cart"} component={Cart} />
            <Route exact path={"/login"} render = {() => <Login handleLogonChange = {this.handleLogonChange}/>} /> 
          </Switch>
        </div>

      </div>
    )
  }
}

This line was modified => <Route exact path={"/login"} render = {() => <Login handleLogonChange = {this.handleLogonChange}/>} />

How to use in Login file:

Login.js

props.handleLogon(){  // (or this.props.handleLogon) if class component
    try{
      if(this.username == "user1" && this.password == "pass123"){
        //send info to app.js
       return true
      }
    }
    catch{
      this.setState({
        message: "Incorrect Credentials"
      });
    }
  }

The basic way to do this, which you should probably try to get an understanding of before moving on to Redux or the Context API, is by passing props . If you aren't already familiar with props , you should head over to the docs for a full explanation.

You pass data from a parent component to a child by simply declaring that data value as a prop when you include the child component in your JSX. You pass data from a child to a parent by passing a function as a prop which can then update the state in the parent.

In your example we can do something like this. We need to use the render method here to pass props to a route:

<Route exact path={"/login"} render={() => <Login handleLogonChange={this.handleLogonChange}/>} />

Then in the Login component, call the function from props:

handleLogon(){
    try{
      if(this.username == "user1" && this.password == "pass123"){
        this.props.handleLogonChange(true);
      }
    }
    catch{
      this.setState({
        message: "Incorrect Credentials"
      });
    }
  }

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