I like the answer regarding passing functions around, its. It's a very handy technique.
On the flip side you can also achieve this using pub/sub or using a variant, a dispatcher, as Flux does. The theory is super simple, have. Have component 5 dispatch a message which component 3 is listening for. Component 3 then updates its state which triggers the re-render. This requires stateful components, which, depending on your viewpoint, may or may not be an anti-pattern. I'm against them personally and would rather that something else is listening for dispatches and changes state from the very top-down (Redux does this, but it adds additional terminology).
import { Dispatcher } from 'flux' import { Component } from 'React' const dispatcher = new Dispatcher() // Component 3 // Some methods, such as constructor, omitted for brevity class StatefulParent extends Component { state = { text: 'foo' } componentDidMount() { dispatcher.register( dispatch => { if ( dispatch.type === 'change' ) { this.setState({ text: 'bar' }) } } } render() { return <h1>{ this.state.text }</h1> } } // Click handler const onClick = event => { dispatcher.dispatch({ type: 'change' }) } // Component 5 in your example const StatelessChild = props => { return <button onClick={ onClick }>Click me</button> } The dispatcher bundles with Flux is very simple, it. It simply registers callbacks and invokes them when any dispatch occurs, passing through the contents on the dispatch (in the above terse example there is no payload with the dispatch, simply a message id). You could adapt this to traditional pub/sub (e.g., using the EventEmitter from events, or some other version) very easily if that makes more sense to you.