There are times, when writing a large scale React application in which one component needs to send a message to another component that it is not a direct descendent or ancestor of, a cousin component, if you will. Two examples that spring to mind are:
- Needing to apply focus to a particular DOM node, which requires a ref to the actual DOM node.
- Needing to make some AJAX call, e.g. submitting a form, using information the receiving component has in its props.
Luckily, if you are writing a large enough React application, you are probably already using some sort of global state management, such as Redux. That’s great, so you have a common state that both components can read from and write to, but how does that help you pass a message? That’s where the world of international espionage comes in…
Draw the curtain and take a seat, Mr. Bond.
To quote Wikipedia:
A dead drop or dead letter box is a method of espionage tradecraft used to pass items or information between two individuals (e.g., a case officer and agent, or two agents) using a secret location, thus not requiring them to meet directly and thereby maintaining operational security. The method stands in contrast to the live drop, so-called because two persons meet to exchange items or information.
You already see where this is going, don’t you? The sending component needs to dispatch an action that will set some slice of the state that the receiving component is listening to. The flow goes like this:
- User interacts with Sender
- Sender dispatches an action to modifiy
state.deaddrop
totrue
or to any value that it wants to pass with the message. - Receiver has
mapStateToProps
with a selector forstate.deaddrop
, and thus gets rerendered with a new prop. - Receiver initiates whatever action is required.
It is important to note here that the flow does not need to begin with a user
interaction. With the rise of asynchronous middleware like redux-saga
and
redux-observable
, the ability to trigger any code on a component anywhere is
very useful.
Implementation
I briefly considered writing a redux-dead-drop
library, even going so far as
“designing” a logo, with its own higher order reducer to enable this
functionality on any reducer and a HOC to connect any component the dead drop
location on the reducer, and even have it call an instance method on its wrapped
component. I'm still reasonably certain that it would be possible to write, but
the design pattern is so simple that it takes hardly any effort to implement it
on any existing reducer, so I rejected abstraction for abstraction's sake.
If you would like to try and implement such a library, help yourself to the name and logo.
As in the world of covert government agents, is important that the Receiver component clear out the dead drop once the message has been received.
I have used this pattern in my redux-form
library to
enable the triggering of a form submission via the dispatch of an action. This
allows the form component to know about how it needs to be submitted and
validated, but also allows any actor in the entire application to trigger the
submission.
This post will self destruct in 5…. 4…. 3….