How to Make Sibling React Components Communicate
The Problem
Let’s say you have a <Comments />
component. Inside it you have two children <CreateComment />
and <ListComments />
. <ListComments />
renders the list of comments passed to it. <CreateComment />
renders an input box. <ListComment />
also renders a reply button next to each comment. When the button is clicked we want to populate our input box in <CreateComment />
with the comment we click on enclosed within double quotes. So basically we need a way to communicate between <ListComments />
and <CreateComment />
You can see the demo of the required behavior in the below codesandbox:
The Solution
There are three ways to do this.
- Lifting the Common State to the Common Parent
- Using Redux/Context
- Using RxJS Subject
Most people are oblivious to the 3rd option and I really prefer the 3rd option in many cases.
Lifting the Common State to the Common Parent
i.e. Lifting the state comment
to <Comments />
Remove the useState()
line from CreateComment.jsx
and add it to Comments
and pass the state as props to the CreateComment
component.
Now you can use setComment
to do the job in handleReply()
The problem with this is that comment
is supposed to be a state that is local to <CreateComment />
. We placed it in the parent component for the sole reason to mutate it in response to an event in a sibling component.
Using Redux/Context
You can do a similar thing with redux where instead of lifting the state to the common parent, you can store it in redux. From <ListComments />
you can issue an action to mutate it and in <CreateComment />
you can access it as you access any other state in redux.
The problem again with this approach is that comment
is supposed to be local to <CreateComment />
but we put it in the global state.
I am not presenting the code for this as this method is extensively covered by many articles out in the internet.
Using RxJS Subject (My Preference)
RxJS subjects allow you to create a stream to which you push events and also subscribe to those events. In our case we’ll create a replyTo$
stream and use it for communication between the siblings.
Send data to <CreateComment />
through the replyTo$
stream
Subscribe to the stream in <CreateComment />
The good thing about this approach is that comment
and setComment()
remains where they should be and you don't have to go to any other file other than CreateComment.jsx
to understand how comment
is being mutated.
Conclusion
We saw three ways to make sibling components communicate in React:
Lifting the Common State to the Common Parent
- Pro: Simple
- Con: The common state gets placed in an unrelated component
Using Redux/Context
- Pro: In cases where the children are nested deeply, avoids prop drilling
- Con: The common state which usually belongs to one component is placed in the global state where many components can potentially access it. For someone new to the codebase, they may not know that only one/two component actually use that state.
Using RxJS Subject
- Pro: Keeps state where it is supposed to be. Can also be used with Redux/Context where the stream variable is placed in redux/context to avoid prop drilling.
- Con: Additional Library
Did I miss to think about anything? Let me know in the comments. Thanks!
Originally published at https://perspectives-blog.netlify.app.