1

Let's say I have the following react code.

<Navigation parentWindow={this} />
<p>Sub Pages</p>
<ReactCSSTransitionGroup
    component="div"
    transitionName="page-transition"
    transitionEnterTimeout={0}
    transitionLeaveTimeout={500}
  >
      {React.cloneElement(this.props.children, {
          key: location.pathname
      })}
  </ReactCSSTransitionGroup>

The ReactCSSTransitionGroup will eventually render a <ContactPage /> which is created by a ContactPage.js. Here's what ContactPage.js looks like:

import React from 'react';

export default class Page extends React.Component
{
    testMe() {alert('Hello World!');}
    render() {return <div>Hello</div>;}
}

From my <Navigation /> which is created by Navigation.js, I want to be able to trigger the ContactPage.testMe(). So I did this in my Navigation.js

import React from 'react';

export default class Page extends React.Component
{
    render() {
        this.props.parentWindow.props.children.testMe();
        return <div>Navigate me</div>;
    }
}

But when I run the project, my Navigation gives me the error:

Uncaught TypeError: this.props.parentWindow.props.children.testCall

How do I get around this problem?

1
  • You have export default class Page extends React.Component in your Navigation.js. Is that just a copy and paste mistake? Commented Nov 4, 2016 at 18:35

1 Answer 1

2

Theoretically you could achieve this by using refs. In the ParentWindow component you would assign a ref to the cloned children, that you would then pass as a prop to the navigation.

React works a bit different than other JS libraries and it forces you to move your business logic, or event logic to the parent component and pass it down as props. What I would suggest is that you pass in a callback function to the Navigation page, that when triggered it calls the ContactPage method.

class Navigation extends React.Component {
  render() {
    this.props.onAlertParent();
    return <div>Navigate me</div>;
  }
}

class ParentWindow extends Component {
  alertChild() {
    if (this.childNode && this.childNode.testMe) {
      this.childNode.testMe();
    }
  }

  render() {
    <div>
      <Navigation onAlertParent={() => this.alertChild()} />
      <p>Sub Pages</p>
      <ReactCSSTransitionGroup
        component="div"
        transitionName="page-transition"
        transitionEnterTimeout={0}
        transitionLeaveTimeout={500}
      >
        {React.cloneElement(this.props.children, {
          key: location.pathname,
          ref: (node) => { this.childNode = node; }
        })}
      </ReactCSSTransitionGroup>
    </div>
  }
}

Notice how the Navigation component receives a callback function via the props, the navigation element doesn't need to know anything about its siblings, it's communicating to them using the parent.

The react way is to communicate between components using props by passing either data or callbacks. There is always a better way to communicate than calling element methods. Even the approach I suggested is flawed since it's still calling a method from an element.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.