简体   繁体   中英

Reactjs: Accessing 'this' of a sibling component

I have a situation where I have 3 components; <View> <Content> and <Footer> .

<View> is parent of <Content> and <Footer> . Now there is a button in <Footer> and when it is clicked, I want to render an Overlay in the <Content> component, so i have to have access to this of the <Content> component inside my <Footer> component. I am not getting on how to accomplish that.

View.js

class View extends Component {
  render() {
    return (
      <div>
        <Content messages={this.props.messages}/>
        <Footer />
      </div>
    )
  }
}

Content.js

class Content extends Component {
  render() {
    return (
      <div>
        {this.props.messages}
      </div>
    )
  }

}

Footer.js

class Footer extends Component {
  constructor(props,context){
    super(props,context);
    this.state = {
      showEmojiPicker: false,
    }
  }

  handleToggleEmojiPicker() {
    this.setState({
      showEmojiPicker: !this.state.showEmojiPicker,
    });
  }

  render() {
    return (
      <div>
        <div>
          <div>
            <bootstrap.Button ref="targetEmojiPicker" bsSize="xsmall" onClick={this.handleToggleEmojiPicker.bind(this)}>
              <bootstrap.Glyphicon glyph="heart" />
            </bootstrap.Button>
              <bootstrap.Overlay
                  show={this.state.showEmojiPicker}
                  onHide={this.handleClose.bind(this)}
                  container={content.this}  //Need this of Content component
                  target={() => ReactDOM.findDOMNode(this.refs.targetEmojiPicker)}
              >
              <EmojiModalCategories actions={this.props.actions}/>
            </bootstrap.Overlay>
          </div>
        </div>
      </div>

    )
  }

}

You should have a read at the Communicate between components page of the official React documentation.

If you want to access a function in the Content component from the Footer you'll have to supply that function as a prop to your Footer from the View .

Assume you want to run the showOverlay() function that's in your Content component, you could do:

View

displayOverlay = () => {
  this.refs.content.showOverlay();
}

render() {
  //some code
  <Content ref="content" />
  //some code
  <Footer overlayButtonClick={this.displayOverlay} />
}

Footer

btnClick = () => {
  this.props.overlayButtonClick();
}    

render() {
  //some code
  <button onClick={this.btnClick}>Click</button>
  //some code
}

Edit August 2017

Note that using string literals for ref value is now deprecated. For more info, you may have a look at an earlier answer I made, here .

If you are using Redux Or Flux better approach would be dispatch some action 'DISPLAY_OVERLAY'. change some reducer or store value to true for example reducer.displayOverlay=true ; and then use that reducer value in your Content component's render method.

  render:function(){
    return <div>
    {reducer.displayOverLay? this.showOverlay():this.hideOverlay()}
    </div>
    } 

if you are not using flux or redux then make use of your view component state. set a state variable showOverlay:false in your view components state. then pass that showOverlay down to Content component

<Content showOverlay={this.state.showOverlay}/>

then

View

toggleOverLay(){
   this.setState({
       showOverlay:!this.state.showOverlay
    })
}
render() {
  //some code
  <Content showOverlay={this.state.showOverlay}/>
  //some code
  <Footer toggleOverlay={this.toggleOverlay} />
}

Footer

 btnClick = () => {
  this.props.toggleOverlay();
}    

render() {
  //some code
  <button onClick={this.btnClick}>Click</button>
  //some code
}

By doing so I got access to 'this' of <Content> in <Footer> component. Now I am not sure if morally I am doing the wrong thing, hurting the Reactjs motive of one-way binding. I'm using redux too, but how can I approach this with the help of store. Suggestions are highly appreciable coz i'm literally confused

View.js

class View extends Component {

  constructor(props,context){
    super(props,context);
    this.state = {
      thisOfContent: false    
    }
  }

  handleUpdateValue(newThisOfContent) {
    this.setState({
      thisOfContent: newThisOfContent
    })  
  }

  render() {
    return (
      <div>
        <Content handleUpdateValue={this.handleUpdateValue.bind(this)}/>
        <Footer stateValue={this.state.thisOfChatWindowContent}/>
      </div>
    )
  }

}

Content.js

class Content extends Component {

  componentDidMount() {
    this.props.handleUpdateValue(this);
  }

  render() {
    return (
      <div>

      </div>
    )
  }

}

Footer.js

class Footer extends Component {
  constructor(props,context){
    super(props,context);
    this.state = {
      showEmojiPicker: false,
    }
  }

  handleToggleEmojiPicker() {
    this.setState({
      showEmojiPicker: !this.state.showEmojiPicker,
    });
  }

  render() {
    return (
      <div>
        <div>
          <div>
            <bootstrap.Button ref="targetEmojiPicker" bsSize="xsmall" onClick={this.handleToggleEmojiPicker.bind(this)}>
              <bootstrap.Glyphicon glyph="heart" />
            </bootstrap.Button>
            <bootstrap.Overlay
                show={this.state.showEmojiPicker}
                onHide={this.handleClose.bind(this)}
                container={this.props.stateValue}
                target={() => ReactDOM.findDOMNode(this.refs.targetEmojiPicker)}
            >
              <EmojiModalCategories actions={this.props.actions}/>
            </bootstrap.Overlay>
          </div>
        </div>
      </div>

    )
  }

}

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