简体   繁体   中英

Passing data from child to parent component not working in react

I am passing data from my child component (Header component) to my parent component (App component). My idea: when I click on my creating button in header component I want to send information to app component to hide header and footer. Here is code example.

Header.jsx:

import React, { Component } from 'react';
import { Nav, Navbar, Button } from "react-bootstrap";

class Header extends Component {

constructor(props) {
    super();
    this.state = {
        showHeaderAndFooter: false
    };
}

onChangeChildComponent = () => {
    this.props.changeVisibilityOfHeaderAndFooter(this.state.showHeaderAndFooter);
}

render() {
    return (  
        <Navbar bg="dark" variant="dark">
            <Nav className="mr-auto">
                <Button href="/createGym" onClick={this.onChangeChildComponent.bind(this)}> Create </Button>
            </Nav>           
        </Navbar>
    );
}
}

export default Header;

App.js:

import React, { Component, Fragment } from 'react';
import './App.css';
import './components/header';
import { BrowserRouter, Route, Switch } from 'react-router-dom';
import Header from './components/header';
import Footer from './components/footer';
import Home from './components/home';
import CreateGym from './components/create-gym';
import Login from './components/authentication/login';

class App extends Component {

constructor() {
    super();
    this.state = {
        showHeaderAndFooter: true
    };
}

onChangeChildComponent (showHeaderAndFooter) {
    this.setState(
    {
        showHeaderAndFooter: showHeaderAndFooter
    });
}

Container = () => (
  <div>
      { this.state.showHeaderAndFooter && 
      <Header 
         changeVisibilityOfHeaderAndFooter = {this.onChangeChildComponent.bind(this)}
      />
      } 
      <div className="container">
          <Route exact path='/' component={Home} />
          <Route path="/createGym" component={CreateGym} />
          <Route path="/login" component={Login} />
      </div>
      { this.state.showHeaderAndFooter && <Footer /> } 
  </div>
  )

render() {
    console.log(this.state.showHeaderAndFooter);
    return (
        <BrowserRouter>
            <Switch>
                <Fragment>
                    { <Route component={this.Container}/> }
                </Fragment>
            </Switch>
        </BrowserRouter>  
    );
}
}

export default App;

The problem is because my code is entering App constructor twice. At the first time, everything is fine, but on the second time, this boolean showHeaderAndFooter is again set to true because that is the default value. Any idea how to solve this?

you shouldn't be passing from child > parent. react is uni-directional (that means data can only flow in one way, and that way is downwards)

to achieve this, move the state into the parent

class Parent extends React = {
   this.state = { showHeaderAndFooter: false }

   functionToToggleShowing = () => {
      this.setState({showHeaderAndFooter: !this.state.showHeaderAndFooter})
   }

  render() {
    return(
        <Child showHeaderAndFooter={this.state.showHeaderAndFooter} functionToToggleShowing={functionToToggleShowing} />
    )
  } 

}

that is pseduo code but essentially move the state to the parent and pass down the state to the child as well as a way to change that state

React allows passing of control from child to parent by means of props.

Here is the 3-step procedure to make it work:

Step 1: Create a data member in Parent, which manipulates parent state.

Step 2: Send the parent's data member as a prop to the child.

Step 3: In the child, Call the prop sent by parent for responding to an event.

Here is a demonstration of passing control from child to parent, using the above technique:

The example has 2 components -

  • Parent component is App.jsx
  • Child component is Header.jsx

Parent has a state-manipulating data member called ' hideHeader '.

Parent passes hideHeader as a prop called onClick to the child.

Child calls the prop sent by parent, in response to its onClick event.

Parent component - App.jsx

import React, { Component } from 'react'
import Header from "./Header";

export default class App extends Component {

  constructor() {
    super();
    this.state = {
      showHeader: true
    }
  }


  {/*  A state-manipulating data member */}

  hideHeader = () => {
    this.setState({showHeader: false})
  }


  render() {
    return (
      <div>

        {/* State-manipulating data member sent as prop to child */}

        { this.state.showHeader &&
            <Header onClick={this.hideHeader} />
        }
      </div>
    )
  }
}

Child component - Header.jsx

import React, { Component } from "react"

export default class Header extends Component {
  render() {
    return (
      <div>
        <h1>Header Demo</h1>

        {/* Call the prop sent by parent when button is clicked */}

        <button onClick={this.props.onClick}>Hide</button>
      </div>
    )
  }
}

Output:

Before 'Hide' button is clicked:

在此处输入图像描述

After 'Hide' button is clicked:

在此处输入图像描述

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