简体   繁体   中英

Wiring between two child components

I'm learning React and I have a specific example of trying to wire two components together through an interface. I have read most of the parent/child, child/parent and sibling component communication stackoverflow related questions and can't seem to find a proper answer.

Say I have an App component that renders a Box and a Mover component. Quite simply, the Box has a move(x,y) function that I'd like the Mover to interface. However, the Mover doesn't have to be a child of Box (or any other relationship) -- specifically, I don't want the Box to pass down its own methods to the Mover.

What I'd like to do in the App, is something like this:

...
render: function() {
    return (
        <Box ref="box"/>
        <Mover box = {this.refs.box} />
    )
}
....

However, you can't use refs in render() as clearly indicated in the docs and the box refs isn't defined anyways until it's mounted (so the box props won't work).

I've thought of using an intermediate object:

...
render: function() {
    var api = {box: undefined};
    return (
        <Box api={api}/>
        <Mover api={api} />
    )
}
....

Where Box sets itself in this.props.api in its componentDidMount method, but that's a little iffy. Another option would be to use the refs callback in the App to do the wiring, but that requires ugly glue code.

Is there any other way to pass references to (yet uncreated) components between each other when rendering them? Or is there some more general design principle that I'm not adhering to?

For siblings, you generally need to move whatever state they both need to reference up into a common parent component and pass it down as props (or sideways into an external storage object - see react-training's Less Simple Communication lesson for an example) and pass it to them as props.

eg if the component rendering Box and Mover had the following state:

getInitialState: function() {
  return {
    x: 0,
    y: 0
  }
}

Then you could pass Mover a callback function which updates it:

handleMove: function(x, y) {
  this.setState({x: x, y: y})
}

// within render() - you could also pass x and y if Mover needs them
<Mover onMove={this.handleMove}/>

// within Mover
this.props.onMove(newX, newY)

If you passed this state to Box as props, it wouldn't necessarily need an explicit move() method (depending on what it does) but could either use the props in its render() method (which would automatically re-render when the props change), or you could react to the x and y values changing by detecting the change with a componentWillReceiveProps() method:

// within render()
<Box x={this.state.x} y={this.state.y}/>

// within Box
componentWillReceiveProps: function(nextProps) {
  if (nextProps.x !== this.props.x || nextProps.y !== this.props.y) {
    // ...
  }
}

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