Manash Sharma
Manash Sharma

Reputation: 29

How to use props properly in react?

There is a button which I have in one of my components named header. I want to hide the navbar component based on that button. I tried creating a prop in the main component shown below which displays all the other components including header and navbar. Below is my main component.

import App from "./graph";
import Navbar from "./navbar";
import Header_Top from "./header";
import Flame from "./section_1";
import Section_3 from "./section_3_graph1";
// import Flame from "./section_test";
import Section_2 from "./section_2";
import Section_5 from "./section_5";
import Section_test from "./section_test";
class main extends Component {
  constructor(props) {
    super(props);
    // this.fullscreenState = this.fullscreenState.bind(this);
  }
  state = {};
  style2 = {
    boxShadow:
      " 0px 0px 40px rgba(255,255,255,0.08),inset 0px 0px 20px rgba(0,0,0,0.3)",
    margin: 5,
    padding: 0,
    textAlign: "center",
    // borderRadius: 20,
  };

  render() {
    var fullscreenState = {
      fullscreen: true,
    };
    return (
      <div
        className="row justify-content-center"
        style={{
          // backgroundColor: "#32373D",
          backgroundImage: "linear-gradient(360deg, #191919, #272A2F)",
        }}
      >
        <Header_Top fullscreenState={fullscreenState} />
        {this.props.fullscreenState.fullscreen === true ? <Navbar /> : null}
        <div className="row col-xl-9 col-lg-9 col-md-12 col-sm-12">
          <div style={this.style1} className="col-xl-12">
            <div className="col-md-12" style={this.style2}>
              <Flame />
            </div>
          </div>
          <div style={this.style1} className="col-xl-4 col-lg-8">
            <div className="col-md-12" style={this.style2}>
              <Section_2 />
            </div>
          </div>
          <div style={this.style1} className="col-xl-8 col-lg-8" ref="inner">
            <div className="col-md-12" style={this.style2}>
              <Section_3 />
            </div>
          </div>
          <div style={this.style1} className="col-xl-12 col-lg-12">
            <div className="col-md-12" style={this.style2}>
              <App />
            </div>
          </div>
        </div>

        <div className="column col-xl-3 col-lg-3 col-md-12 col-sm-12 ">
          <div style={this.style1} className="col-xl-12 col-lg-12 my-auto">
            <div className="col-md-12" style={this.style2}>
              <Section_5 />
            </div>
          </div>
          <div style={this.style1} className="col-xl-12 col-lg-12">
            <div className="col-md-12" style={this.style2}>
              <Section_test />
            </div>
          </div>
        </div>
      </div>
    );
  }
}

export default main;

This is my header component:


class Header_Top extends Component {
  state = {
    fullscreen: true,
  };

  toggleFullScreen = () => {
    let fullscreen = this.props.fullscreenState.fullscreen;
    this.setState({
      fullscreen: !fullscreen,
    });
  };

  changeLabel() {
    let Label = "";
    Label +=
      this.props.fullscreenState.fullscreen === true
        ? "Exit full Screen"
        : "Go to full Screen";
    return Label;
  }
  render() {
    return (
      <div className="d-none d-md-block " style={{ width: "100%" }}>
        <nav class="navbar navbar-expand-md navbar-light bg-light">
          <a class="navbar-brand" href="#">
            <img
              src={require("./images/logo.png")}
              width="50"
              // height="50"
              class="img-responsive"
              alt=""
              style={{}}
            />
          </a>
          <a class="navbar-brand" href="#">
            <h1>SolarSenz</h1>
          </a>
          <button
            class="navbar-toggler"
            type="button"
            data-toggle="collapse"
            data-target="#navbarNavDropdown"
            aria-controls="navbarNavDropdown"
            aria-expanded="false"
            aria-label="Toggle navigation"
          >
            <span class="navbar-toggler-icon"></span>
          </button>
          <div class="collapse navbar-collapse" id="navbarNavDropdown">
            <ul class="navbar-nav ml-auto">
              <li className="nav-item">
                <button
                  className="btn btn-outline-dark"
                  onClick={this.toggleFullScreen}
                >
                  {this.changeLabel()}
                </button>
              </li>
              <li class="nav-item dropdown">
                <a
                  class="nav-link dropdown-toggle active"
                  href="#"
                  id="navbarDropdownMenuLink"
                  data-toggle="dropdown"
                  aria-haspopup="true"
                  aria-expanded="false"
                >
                  Admin Console<span class="sr-only">(current)</span>
                </a>
                <div
                  class="dropdown-menu"
                  aria-labelledby="navbarDropdownMenuLink"
                >
                  <a class="dropdown-item" href="#">
                    Action
                  </a>
                  <a class="dropdown-item" href="#">
                    Another action
                  </a>
                  <a class="dropdown-item" href="#">
                    Something else here
                  </a>
                </div>
              </li>
            </ul>
          </div>
          <a class="navbar-brand" href="#">
            <img
              src={require("./images/logo.png")}
              width="50"
              // height="50"
              class="img-responsive"
              alt=""
              style={{}}
            />
          </a>
        </nav>
      </div>
    );
  }
}

export default Header_Top;

I keep getting the error

TypeError: Cannot read property 'fullscreen' of undefined

What does this mean and how can I fix it?

Upvotes: 0

Views: 86

Answers (1)

D10S
D10S

Reputation: 1549

The error you are getting is due to the following line (in 'render' function of class 'main'):

{this.props.fullscreenState.fullscreen === true ? <Navbar /> : null}

As the error indicates "this.props.fullscreenState" is udefined.

Props are arguments passed into React components. If no prop called "fullscreenState" was passed to class "main", it will be undefined.

What your are probably should do is to create state for the 'main' class which should include 'fullscreenState'. Then add this class a function that will toggle the state and pass it, together with the 'fullscreenState' to the 'header' component:

import App from "./graph";
import Navbar from "./navbar";
import Header_Top from "./header";
import Flame from "./section_1";
import Section_3 from "./section_3_graph1";
// import Flame from "./section_test";
import Section_2 from "./section_2";
import Section_5 from "./section_5";
import Section_test from "./section_test";
class main extends Component {
    constructor(props) {
        super(props);
        this.state = {
            fullscreen: false
        }
        // this.fullscreenState = this.fullscreenState.bind(this);
    }
    style2 = {
        boxShadow: " 0px 0px 40px rgba(255,255,255,0.08),inset 0px 0px 20px rgba(0,0,0,0.3)",
        margin: 5,
        padding: 0,
        textAlign: "center",
        // borderRadius: 20,
    };

    toggleFullScreen = this.setState({fullscreen: !this.state.fullscreen});

    render() {
        return (
            <div
                className="row justify-content-center"
                style={{
                    // backgroundColor: "#32373D",
                    backgroundImage: "linear-gradient(360deg, #191919, #272A2F)",
                }}
            >
                <Header_Top fullscreenState={this.state.fullscreenState} toggleFullScreen={toggleFullScreen} />
                {this.props.fullscreenState.fullscreen === true ? <Navbar /> : null}
                <div className="row col-xl-9 col-lg-9 col-md-12 col-sm-12">
                    <div style={this.style1} className="col-xl-12">
                        <div className="col-md-12" style={this.style2}>
                            <Flame />
                        </div>
                    </div>
                    <div style={this.style1} className="col-xl-4 col-lg-8">
                        <div className="col-md-12" style={this.style2}>
                            <Section_2 />
                        </div>
                    </div>
                    <div style={this.style1} className="col-xl-8 col-lg-8" ref="inner">
                        <div className="col-md-12" style={this.style2}>
                            <Section_3 />
                        </div>
                    </div>
                    <div style={this.style1} className="col-xl-12 col-lg-12">
                        <div className="col-md-12" style={this.style2}>
                            <App />
                        </div>
                    </div>
                </div>

                <div className="column col-xl-3 col-lg-3 col-md-12 col-sm-12 ">
                    <div style={this.style1} className="col-xl-12 col-lg-12 my-auto">
                        <div className="col-md-12" style={this.style2}>
                            <Section_5 />
                        </div>
                    </div>
                    <div style={this.style1} className="col-xl-12 col-lg-12">
                        <div className="col-md-12" style={this.style2}>
                            <Section_test />
                        </div>
                    </div>
                </div>
            </div>
        );
    }
}

export default main;

Now in the header you don't need the state as you can use the 'fullscreenstate' prop and in the toggle function in the header change so it wil caontain the call of the toggle function of the 'main' component. something like this:

class Header_Top extends Component {

  toggleFullScreen = () => {
    this.props.toggleFullScreen
 };

Don't copy-paste what I've done as there might be syntax error as I've been using functional components in the last few months.

Upvotes: 1

Related Questions