In this how-to guide, we will be going over how to communicate between two separate blocks.
Sometimes, it may be necessary for one block to send information to another block on the same page. In Element, blocks can communicate with each other via a pub-sub mechanism. This guide will explain how to send information between two (or more) blocks.
All blocks have access to an instance of PubSubJS as this.props.pubSub.
For more details on PubSubJS, see the PubSubJS npm reference.
The first step of setting up block communication is figuring out which block will send messages (the sender), and which blocks will receive those messages (the receivers). In Element, some pre-made blocks already send messages to each other, and you can listen for those events in your blocks. For more information, see "Cart Events."
For this guide, you will be setting up your own blocks as senders and receivers of messages.
Once you have identified which block will send messages to other blocks, you need to set up a publish action in that block's code.
For this guide, we'll use the example of sending a message between blocks when a user changed an option for a product they were viewing.
Send your message using utils.pubSub.publish() in your block. This function takes two arguments:
Example:
// in your block component body, add a function. Here we're doing it as an instance property because this component is a class.
handleOptionChange = event => {
const newOptionValue = event.target.value
this.props.pubSub.publish('myEvents_PRODUCT_OPTION_CHANGED', newOptionValue)
}
Note: If your component is a stateless functional component rather than an ES6 class, you would define your function as a const rather than an instance property.
It's always a good idea to add a unique prefix to topic names that you create to ensure that you don't collide with any other existing topic names. This way, your events will all live in their own namespace. In this example, our topic is named myEvents_PRODUCT_OPTION_CHANGED, and myEvents_ is the prefix we have chosen. You should choose something descriptive and unique.
You can call your function from anywhere else in your block code. For this example, you would call this.handleOptionChange from the onChange event for a select element, like so:
<select onChange={this.handleOptionChange}>
At this point, you have a block that's sending messages, but you need to set up one or more blocks to listen for those messages.
Locate the componentDidMount function of one of your receiver blocks. If this function doesn't exist yet, add it to your component. You may need to refactor the block to use class syntax. Then add a subscription:
componentDidMount() {
this.props.pubSub.subscribe(
'myEvents_PRODUCT_OPTION_CHANGED', // must match the topic name EXACTLY
this.onOptionChanged
);
}
utils.pubSub.subscribe() takes two arguments:
Your handler function is the code that actually does something with the data received from another block. Add it to your block component as an instance property.
// inside the body of your component
onOptionChanged = (msg, newOptionValue) => {
// do something with newOptionValue. In this example we will set it to state.
this.setState({ productOption: newOptionValue })
}
Repeat this process for more receiver blocks, if necessary.
To set up your blocks to listen for existing messages, see "Cart Events."