1

I saw a few similar questions, but about parent/child elements, i have that kind of node tree:

IndexPage -> Modals -> ClientDetails(it's modal component)
          -> Header

I want to call ClientDetails.openModal inside Header, tried many ways like creating refs for ClientDetails in indexPage and then pass indexPage to header like prop, but it's works strange, i see refs of props.IndexPage, but when trying access refs directly it's underfind

enter image description here enter image description here

class IndexPage extends React.Component {
  constructor(props) {
    super(props);

    this.modals = React.createRef();
  }

  render() {
    return (
      <Layout>
        <SEO/>
        <Header indexPage={this}/>
        <Story/>
        <Products/>
        <Clients/>
        <Reviews/>
        <Partners/>
        <Footer/>
        <Modals ref={this.modals} />
      </Layout>
    )
  }
}
class Modals extends React.Component {
  constructor(props) {
    super(props);
    this.clientDetailsRef = React.createRef();
  }

  render() {
    return (
      <>
        <ThankYou/>
        <ContactDetails ref={this.clientDetailsRef}/>
      </>
    )
  }
}
class Header extends React.Component {
  constructor(props) {
    super(props);
    this.state = { isActive: false, isSticky: false };
    this.toggle = this.toggle.bind(this);


    this.indexPage = props.indexPage
    console.log(this.indexPage)
    console.log(this.indexPage.modals)
  }
}
Roni_sl
  • 25
  • 5
  • You say you tried refs. Did you try `ref.current`? – TKoL Dec 18 '19 at 14:50
  • For example this answer: https://stackoverflow.com/a/24848228/1959054 – TKoL Dec 18 '19 at 14:50
  • Yeah, i did ref for ClientDetails in Modals, and for Modals in IndexPage, then passed IndexPage as a prop, and problem is in Header i can't get that refs through IndexPage – Roni_sl Dec 18 '19 at 14:56
  • I can't see the structure of your code so I'm not really sure what you're doing in Header and where you're getting the ref from – TKoL Dec 18 '19 at 14:57
  • Look at two pictures attached, indexPage has modals(it's ref) and when i log indexPage.modals it's null – Roni_sl Dec 18 '19 at 15:01
  • The pictures don't tell me what your code looks like. How are you passing the prop to the Header? How are you getting the ref in the first place? Posting pictures of your console won't help us help you – TKoL Dec 18 '19 at 15:04
  • Sorry, attached a code – Roni_sl Dec 18 '19 at 15:07
  • By the time you're in the constructor of Header, the `modals` property might not actually be defined yet – TKoL Dec 18 '19 at 15:14

3 Answers3

1

Here is a small fiddle for calling a child function from the parent

https://jsfiddle.net/c1qfn9Lx/9/

class Modal extends React.Component {
 constructor(props) {
  super(props);
  this.state= {
   showModal: false
  }
  this.toggleModal = this.toggleModal.bind(this)
 }
 toggleModal() {this.setState({showModal: !this.state.showModal})}

render() {
 const { showModal } = this.state;
 return(
  <div className="modal">
   {showModal && 
    <div>
     Showing modal
    </div>
   }
  </div>
 )
 }
}

class TodoApp extends React.Component {
 constructor(props) {
   super(props)
   this.modalRef = React.createRef()
   this.handleClick = this.handleClick.bind(this);
 }

 handleClick() {
  this.modalRef.current.toggleModal();
 }

 render() {
   return (
     <div className="parent">
       <Modal ref={this.modalRef} />
       <button onClick={this.handleClick}>Click</button>
     </div>
   )
 }
}

ReactDOM.render(<TodoApp />, document.querySelector("#app"))

vtolentino
  • 754
  • 5
  • 14
1

I think you can solve your problem using react.js context. You wanted to control the Modals component in the Header component. So you tried to reference the Modals component toggle function in the Header component to solve the problem. I think it is a fine solution. But in my opinion, sharing state in peer components is also another solution. So you can use react.js context to share states between two peer components in a parent component of them. I think doing this is following react declarative programming.

Please check this code

Daniel Li
  • 170
  • 1
  • 12
0

I would try doing this:

class IndexPage extends React.Component {
  constructor(props) {
    super(props);

    this.state = {modalsRef: null};
  }

  render() {
    return (
      <Layout>
        <SEO/>
        <Header modalsRef={this.state.modalsRef}/>
        <Story/>
        <Products/>
        <Clients/>
        <Reviews/>
        <Partners/>
        <Footer/>
        <Modals ref={r => !this.state.modalsRef && this.setState({modalsRef:r})} />
      </Layout>
    )
  }
}

But please note: the property won't work in the constructor of Header most likely. It should work though by the time you're doing things like Button.onClick callbacks.

TKoL
  • 13,158
  • 3
  • 39
  • 73